From fca18a26439037fb6a9e51fbe8cb5155fc79f05e Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:23 +0200 Subject: [PATCH 01/16] tegra30: clock: add EXTPERIPH This mappings were missing for some reason. Tested-by: Svyatoslav Ryhel # LG P895 T30 Signed-off-by: Svyatoslav Ryhel Reviewed-by: Simon Glass Signed-off-by: Tom --- arch/arm/include/asm/arch-tegra30/clock-tables.h | 6 +++--- arch/arm/mach-tegra/tegra30/clock.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/include/asm/arch-tegra30/clock-tables.h b/arch/arm/include/asm/arch-tegra30/clock-tables.h index 8588009c61..6c899ff64c 100644 --- a/arch/arm/include/asm/arch-tegra30/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra30/clock-tables.h @@ -190,9 +190,9 @@ enum periph_id { PERIPH_ID_ACTMON, /* 24 */ - PERIPH_ID_EX_RESERVED24, - PERIPH_ID_EX_RESERVED25, - PERIPH_ID_EX_RESERVED26, + PERIPH_ID_EXTPERIPH1, + PERIPH_ID_EXTPERIPH2, + PERIPH_ID_EXTPERIPH3, PERIPH_ID_EX_RESERVED27, PERIPH_ID_SATA, PERIPH_ID_HDA, diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c index 449b66e3b2..04ad5c504d 100644 --- a/arch/arm/mach-tegra/tegra30/clock.c +++ b/arch/arm/mach-tegra/tegra30/clock.c @@ -377,9 +377,9 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = { PERIPHC_ACTMON, /* 24 */ - NONE(RESERVED24), - NONE(RESERVED25), - NONE(RESERVED26), + PERIPHC_EXTPERIPH1, + PERIPHC_EXTPERIPH2, + PERIPHC_EXTPERIPH3, NONE(RESERVED27), PERIPHC_SATA, PERIPHC_HDA, From 2fafac30efb9bb911b6e7159a02c080bccc9ae23 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:24 +0200 Subject: [PATCH 02/16] ARM: t20/t30: swap host1x and disp1 clock parents According to mainline clock tables and TRM HOST1X parent is PLLC, while DISP1 usually uses PLLP as parent clock. Tested-by: Andreas Westman Dorcsak # ASUS TF T30 Tested-by: Robert Eckelmann # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel # LG P895 T30 Tested-by: Thierry Reding # Beaver T30 Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/mach-tegra/tegra20/clock.c | 4 ++-- arch/arm/mach-tegra/tegra30/clock.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-tegra/tegra20/clock.c b/arch/arm/mach-tegra/tegra20/clock.c index 8c127430aa..0316073d1a 100644 --- a/arch/arm/mach-tegra/tegra20/clock.c +++ b/arch/arm/mach-tegra/tegra20/clock.c @@ -760,8 +760,8 @@ struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SBC2, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC3, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC4, CLOCK_ID_PERIPH }, - { PERIPH_ID_HOST1X, CLOCK_ID_PERIPH }, - { PERIPH_ID_DISP1, CLOCK_ID_CGENERAL }, + { PERIPH_ID_HOST1X, CLOCK_ID_CGENERAL }, + { PERIPH_ID_DISP1, CLOCK_ID_PERIPH }, { PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC1, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH }, diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c index 04ad5c504d..e5c2fd542c 100644 --- a/arch/arm/mach-tegra/tegra30/clock.c +++ b/arch/arm/mach-tegra/tegra30/clock.c @@ -799,8 +799,8 @@ struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SBC4, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC5, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC6, CLOCK_ID_PERIPH }, - { PERIPH_ID_HOST1X, CLOCK_ID_PERIPH }, - { PERIPH_ID_DISP1, CLOCK_ID_CGENERAL }, + { PERIPH_ID_HOST1X, CLOCK_ID_CGENERAL }, + { PERIPH_ID_DISP1, CLOCK_ID_PERIPH }, { PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC1, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH }, From 65e02744ec1517eefb20354db61ddbd9560aba2c Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:25 +0200 Subject: [PATCH 03/16] ARM: tegra: clock: add clk_id_to_pll_id helper This function allows to convert a device tree clock ID to PLL ID. Tested-by: Andreas Westman Dorcsak # ASUS TF T30 Tested-by: Robert Eckelmann # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel # HTC One X Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/include/asm/arch-tegra/clock.h | 8 ++++++ arch/arm/mach-tegra/tegra114/clock.c | 37 ++++++++++++++++++++++++ arch/arm/mach-tegra/tegra124/clock.c | 38 +++++++++++++++++++++++++ arch/arm/mach-tegra/tegra20/clock.c | 37 ++++++++++++++++++++++++ arch/arm/mach-tegra/tegra210/clock.c | 37 ++++++++++++++++++++++++ arch/arm/mach-tegra/tegra30/clock.c | 37 ++++++++++++++++++++++++ 6 files changed, 194 insertions(+) diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h index 1dd5d0742c..2270501406 100644 --- a/arch/arm/include/asm/arch-tegra/clock.h +++ b/arch/arm/include/asm/arch-tegra/clock.h @@ -354,6 +354,14 @@ int get_periph_clock_source(enum periph_id periph_id, */ enum periph_id clk_id_to_periph_id(int clk_id); +/* + * Convert a device tree clock ID to our PLL ID. + * + * @param clk_id Clock ID according to tegra device tree binding + * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid + */ +enum clock_id clk_id_to_pll_id(int clk_id); + /** * Set the output frequency you want for each PLL clock. * PLL output frequencies are programmed by setting their N, M and P values. diff --git a/arch/arm/mach-tegra/tegra114/clock.c b/arch/arm/mach-tegra/tegra114/clock.c index 143f86863f..15c2adc417 100644 --- a/arch/arm/mach-tegra/tegra114/clock.c +++ b/arch/arm/mach-tegra/tegra114/clock.c @@ -19,6 +19,8 @@ #include #include +#include + /* * Clock types that we can use as a source. The Tegra114 has muxes for the * peripheral clocks, and in most cases there are four options for the clock @@ -646,6 +648,41 @@ enum periph_id clk_id_to_periph_id(int clk_id) return clk_id; } } + +/* + * Convert a device tree clock ID to our PLL ID. + * + * @param clk_id Clock ID according to tegra114 device tree binding + * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid + */ +enum clock_id clk_id_to_pll_id(int clk_id) +{ + switch (clk_id) { + case TEGRA114_CLK_PLL_C: + return CLOCK_ID_CGENERAL; + case TEGRA114_CLK_PLL_M: + return CLOCK_ID_MEMORY; + case TEGRA114_CLK_PLL_P: + return CLOCK_ID_PERIPH; + case TEGRA114_CLK_PLL_A: + return CLOCK_ID_AUDIO; + case TEGRA114_CLK_PLL_U: + return CLOCK_ID_USB; + case TEGRA114_CLK_PLL_D: + case TEGRA114_CLK_PLL_D_OUT0: + return CLOCK_ID_DISPLAY; + case TEGRA114_CLK_PLL_X: + return CLOCK_ID_XCPU; + case TEGRA114_CLK_PLL_E_OUT0: + return CLOCK_ID_EPCI; + case TEGRA114_CLK_CLK_32K: + return CLOCK_ID_32KHZ; + case TEGRA114_CLK_CLK_M: + return CLOCK_ID_CLK_M; + default: + return CLOCK_ID_NONE; + } +} #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ void clock_early_init(void) diff --git a/arch/arm/mach-tegra/tegra124/clock.c b/arch/arm/mach-tegra/tegra124/clock.c index da38b26c27..415ba15e5d 100644 --- a/arch/arm/mach-tegra/tegra124/clock.c +++ b/arch/arm/mach-tegra/tegra124/clock.c @@ -19,6 +19,9 @@ #include #include +#include +#include + /* * Clock types that we can use as a source. The Tegra124 has muxes for the * peripheral clocks, and in most cases there are four options for the clock @@ -826,6 +829,41 @@ enum periph_id clk_id_to_periph_id(int clk_id) return clk_id; } } + +/* + * Convert a device tree clock ID to our PLL ID. + * + * @param clk_id Clock ID according to tegra124 device tree binding + * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid + */ +enum clock_id clk_id_to_pll_id(int clk_id) +{ + switch (clk_id) { + case TEGRA124_CLK_PLL_C: + return CLOCK_ID_CGENERAL; + case TEGRA124_CLK_PLL_M: + return CLOCK_ID_MEMORY; + case TEGRA124_CLK_PLL_P: + return CLOCK_ID_PERIPH; + case TEGRA124_CLK_PLL_A: + return CLOCK_ID_AUDIO; + case TEGRA124_CLK_PLL_U: + return CLOCK_ID_USB; + case TEGRA124_CLK_PLL_D: + case TEGRA124_CLK_PLL_D_OUT0: + return CLOCK_ID_DISPLAY; + case TEGRA124_CLK_PLL_X: + return CLOCK_ID_XCPU; + case TEGRA124_CLK_PLL_E: + return CLOCK_ID_EPCI; + case TEGRA124_CLK_CLK_32K: + return CLOCK_ID_32KHZ; + case TEGRA124_CLK_CLK_M: + return CLOCK_ID_CLK_M; + default: + return CLOCK_ID_NONE; + } +} #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ void clock_early_init(void) diff --git a/arch/arm/mach-tegra/tegra20/clock.c b/arch/arm/mach-tegra/tegra20/clock.c index 0316073d1a..593622bfdc 100644 --- a/arch/arm/mach-tegra/tegra20/clock.c +++ b/arch/arm/mach-tegra/tegra20/clock.c @@ -20,6 +20,8 @@ #include #include +#include + /* * Clock types that we can use as a source. The Tegra20 has muxes for the * peripheral clocks, and in most cases there are four options for the clock @@ -578,6 +580,41 @@ enum periph_id clk_id_to_periph_id(int clk_id) return clk_id; } } + +/* + * Convert a device tree clock ID to our PLL ID. + * + * @param clk_id Clock ID according to tegra20 device tree binding + * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid + */ +enum clock_id clk_id_to_pll_id(int clk_id) +{ + switch (clk_id) { + case TEGRA20_CLK_PLL_C: + return CLOCK_ID_CGENERAL; + case TEGRA20_CLK_PLL_M: + return CLOCK_ID_MEMORY; + case TEGRA20_CLK_PLL_P: + return CLOCK_ID_PERIPH; + case TEGRA20_CLK_PLL_A: + return CLOCK_ID_AUDIO; + case TEGRA20_CLK_PLL_U: + return CLOCK_ID_USB; + case TEGRA20_CLK_PLL_D: + case TEGRA20_CLK_PLL_D_OUT0: + return CLOCK_ID_DISPLAY; + case TEGRA20_CLK_PLL_X: + return CLOCK_ID_XCPU; + case TEGRA20_CLK_PLL_E: + return CLOCK_ID_EPCI; + case TEGRA20_CLK_CLK_32K: + return CLOCK_ID_32KHZ; + case TEGRA20_CLK_CLK_M: + return CLOCK_ID_CLK_M; + default: + return CLOCK_ID_NONE; + } +} #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ void clock_early_init(void) diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c index 330753f2ad..76fbfef580 100644 --- a/arch/arm/mach-tegra/tegra210/clock.c +++ b/arch/arm/mach-tegra/tegra210/clock.c @@ -22,6 +22,8 @@ #include #include +#include + /* * Clock types that we can use as a source. The Tegra210 has muxes for the * peripheral clocks, and in most cases there are four options for the clock @@ -914,6 +916,41 @@ enum periph_id clk_id_to_periph_id(int clk_id) return clk_id; } } + +/* + * Convert a device tree clock ID to our PLL ID. + * + * @param clk_id Clock ID according to tegra210 device tree binding + * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid + */ +enum clock_id clk_id_to_pll_id(int clk_id) +{ + switch (clk_id) { + case TEGRA210_CLK_PLL_C: + return CLOCK_ID_CGENERAL; + case TEGRA210_CLK_PLL_M: + return CLOCK_ID_MEMORY; + case TEGRA210_CLK_PLL_P: + return CLOCK_ID_PERIPH; + case TEGRA210_CLK_PLL_A: + return CLOCK_ID_AUDIO; + case TEGRA210_CLK_PLL_U: + return CLOCK_ID_USB; + case TEGRA210_CLK_PLL_D: + case TEGRA210_CLK_PLL_D_OUT0: + return CLOCK_ID_DISPLAY; + case TEGRA210_CLK_PLL_X: + return CLOCK_ID_XCPU; + case TEGRA210_CLK_PLL_E: + return CLOCK_ID_EPCI; + case TEGRA210_CLK_CLK_32K: + return CLOCK_ID_32KHZ; + case TEGRA210_CLK_CLK_M: + return CLOCK_ID_CLK_M; + default: + return CLOCK_ID_NONE; + } +} #endif /* CONFIG_OF_CONTROL */ /* diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c index e5c2fd542c..dcdd0d0978 100644 --- a/arch/arm/mach-tegra/tegra30/clock.c +++ b/arch/arm/mach-tegra/tegra30/clock.c @@ -19,6 +19,8 @@ #include #include +#include + /* * Clock types that we can use as a source. The Tegra30 has muxes for the * peripheral clocks, and in most cases there are four options for the clock @@ -628,6 +630,41 @@ enum periph_id clk_id_to_periph_id(int clk_id) return clk_id; } } + +/* + * Convert a device tree clock ID to our PLL ID. + * + * @param clk_id Clock ID according to tegra30 device tree binding + * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid + */ +enum clock_id clk_id_to_pll_id(int clk_id) +{ + switch (clk_id) { + case TEGRA30_CLK_PLL_C: + return CLOCK_ID_CGENERAL; + case TEGRA30_CLK_PLL_M: + return CLOCK_ID_MEMORY; + case TEGRA30_CLK_PLL_P: + return CLOCK_ID_PERIPH; + case TEGRA30_CLK_PLL_A: + return CLOCK_ID_AUDIO; + case TEGRA30_CLK_PLL_U: + return CLOCK_ID_USB; + case TEGRA30_CLK_PLL_D: + case TEGRA30_CLK_PLL_D_OUT0: + return CLOCK_ID_DISPLAY; + case TEGRA30_CLK_PLL_X: + return CLOCK_ID_XCPU; + case TEGRA30_CLK_PLL_E: + return CLOCK_ID_EPCI; + case TEGRA30_CLK_CLK_32K: + return CLOCK_ID_32KHZ; + case TEGRA30_CLK_CLK_M: + return CLOCK_ID_CLK_M; + default: + return CLOCK_ID_NONE; + } +} #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ void clock_early_init(void) From a81d792479340bf03131111b285c0f70d27622b6 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:26 +0200 Subject: [PATCH 04/16] ARM: tegra: clock: add clock_decode_pair helper Get periph clock id and its parent from device tree. This works by looking up the peripheral's 'clocks' node and reading out the second and fourth cells, which are the peripheral and PLL clock numbers. Tested-by: Andreas Westman Dorcsak # ASUS TF T30 Tested-by: Robert Eckelmann # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel # HTC One X Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/include/asm/arch-tegra/clock.h | 13 +++++++++++++ arch/arm/mach-tegra/clock.c | 23 +++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h index 2270501406..61ef81e7fe 100644 --- a/arch/arm/include/asm/arch-tegra/clock.h +++ b/arch/arm/include/asm/arch-tegra/clock.h @@ -270,6 +270,19 @@ void clock_ll_start_uart(enum periph_id periph_id); */ int clock_decode_periph_id(struct udevice *dev); +/** + * Get periph clock id and its parent from device tree. + * + * This works by looking up the peripheral's 'clocks' node and reading out + * the second and fourth cells, which are the peripheral and PLL clock numbers. + * + * @param dev udevice associated with FDT node + * @param clk_id pointer to int array of 2 values + * first is periph clock, second is + * its PLL parent according to FDT. + */ +int clock_decode_pair(struct udevice *dev, int *clk_id); + /** * Checks if the oscillator bypass is enabled (XOBP bit) * diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 11bffc1701..966009f375 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -678,6 +678,29 @@ int clock_decode_periph_id(struct udevice *dev) assert(clock_periph_id_isvalid(id)); return id; } + +/* + * Get periph clock id and its parent from device tree. + * + * @param dev udevice associated with FDT node + * @param clk_id pointer to u32 array of 2 values + * first is periph clock, second is + * its PLL parent according to FDT. + */ +int clock_decode_pair(struct udevice *dev, int *clk_id) +{ + u32 cell[4]; + int err; + + err = dev_read_u32_array(dev, "clocks", cell, ARRAY_SIZE(cell)); + if (err) + return -EINVAL; + + clk_id[0] = clk_id_to_periph_id(cell[1]); + clk_id[1] = clk_id_to_pll_id(cell[3]); + + return 0; +} #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ int clock_verify(void) From 678157e212ea9871e03896adf3297ebb61c912db Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:27 +0200 Subject: [PATCH 05/16] ARM: tegra30: add PLLD to pll setup On T30 unlike T20 dsi panels are wider used on devices and PLLD is used as DISP1 parent more often, so lets enable it as well for this cases. Tested-by: Andreas Westman Dorcsak # ASUS TF700T T30 Tested-by: Svyatoslav Ryhel # HTC One X T30 Tested-by: Thierry Reding # Beaver T30 Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/mach-tegra/tegra30/clock.c | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c index dcdd0d0978..b66211ce94 100644 --- a/arch/arm/mach-tegra/tegra30/clock.c +++ b/arch/arm/mach-tegra/tegra30/clock.c @@ -669,7 +669,48 @@ enum clock_id clk_id_to_pll_id(int clk_id) void clock_early_init(void) { + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + struct clk_pll_info *pllinfo; + u32 data; + tegra30_set_up_pllp(); + + /* + * PLLD output frequency set to 925Mhz + */ + switch (clock_get_osc_freq()) { + case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ + case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */ + clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12); + break; + + case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ + clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12); + break; + + case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */ + case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */ + clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12); + break; + + case CLOCK_OSC_FREQ_19_2: + case CLOCK_OSC_FREQ_38_4: + default: + /* + * These are not supported. It is too early to print a + * message and the UART likely won't work anyway due to the + * oscillator being wrong. + */ + break; + } + + /* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1, and enable lock */ + pllinfo = &tegra_pll_info_table[CLOCK_ID_DISPLAY]; + data = (12 << pllinfo->kcp_shift) | (1 << pllinfo->kvco_shift); + data |= (1 << PLLD_CLKENABLE) | (1 << pllinfo->lock_ena); + writel(data, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc); + udelay(2); } void arch_timer_init(void) From 23d24df34cdd8157d10d302dbba798cd0b518451 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:28 +0200 Subject: [PATCH 06/16] ARM: tegra: Fix Tegra PWM parent clock Default parent clock for the PWM on Tegra is a 32kHz clock and is unable to support the requested PWM period. Fix PWM support on Tegra20, Tegra30, Tegra114, Tegra124 and Tegra210 by updating the parent clock for the PWM to be the PLL_P. This commit is equivalent to Linux kernel commit: https://lore.kernel.org/all/20221010100046.6477-1-jonathanh@nvidia.com/ Tested-by: Andreas Westman Dorcsak # ASUS TF T30 Tested-by: Robert Eckelmann # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel # ASUS TF201 T30 Tested-by: Thierry Reding # T30 and T124 Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/dts/tegra114.dtsi | 2 +- arch/arm/dts/tegra124.dtsi | 2 +- arch/arm/mach-tegra/tegra114/clock.c | 2 +- arch/arm/mach-tegra/tegra124/clock.c | 2 +- arch/arm/mach-tegra/tegra20/clock.c | 2 +- arch/arm/mach-tegra/tegra210/clock.c | 2 +- arch/arm/mach-tegra/tegra30/clock.c | 2 +- drivers/pwm/tegra_pwm.c | 10 ++++++---- 8 files changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/arm/dts/tegra114.dtsi b/arch/arm/dts/tegra114.dtsi index 8932ea3afd..68ee7f3165 100644 --- a/arch/arm/dts/tegra114.dtsi +++ b/arch/arm/dts/tegra114.dtsi @@ -312,7 +312,7 @@ }; pwm: pwm@7000a000 { - compatible = "nvidia,tegra114-pwm", "nvidia,tegra20-pwm"; + compatible = "nvidia,tegra114-pwm"; reg = <0x7000a000 0x100>; #pwm-cells = <2>; clocks = <&tegra_car TEGRA114_CLK_PWM>; diff --git a/arch/arm/dts/tegra124.dtsi b/arch/arm/dts/tegra124.dtsi index f473ba28e4..ffec9cae09 100644 --- a/arch/arm/dts/tegra124.dtsi +++ b/arch/arm/dts/tegra124.dtsi @@ -377,7 +377,7 @@ }; pwm: pwm@7000a000 { - compatible = "nvidia,tegra124-pwm", "nvidia,tegra20-pwm"; + compatible = "nvidia,tegra124-pwm", "nvidia,tegra114-pwm"; reg = <0x7000a000 0x100>; #pwm-cells = <2>; clocks = <&tegra_car TEGRA124_CLK_PWM>; diff --git a/arch/arm/mach-tegra/tegra114/clock.c b/arch/arm/mach-tegra/tegra114/clock.c index 15c2adc417..8ad71f590f 100644 --- a/arch/arm/mach-tegra/tegra114/clock.c +++ b/arch/arm/mach-tegra/tegra114/clock.c @@ -782,7 +782,7 @@ struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH }, - { PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ }, + { PERIPH_ID_PWM, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C1, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C2, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C3, CLOCK_ID_PERIPH }, diff --git a/arch/arm/mach-tegra/tegra124/clock.c b/arch/arm/mach-tegra/tegra124/clock.c index 415ba15e5d..ca9549a318 100644 --- a/arch/arm/mach-tegra/tegra124/clock.c +++ b/arch/arm/mach-tegra/tegra124/clock.c @@ -1208,7 +1208,7 @@ struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH }, - { PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ }, + { PERIPH_ID_PWM, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C1, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C2, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C3, CLOCK_ID_PERIPH }, diff --git a/arch/arm/mach-tegra/tegra20/clock.c b/arch/arm/mach-tegra/tegra20/clock.c index 593622bfdc..067a9f1a2f 100644 --- a/arch/arm/mach-tegra/tegra20/clock.c +++ b/arch/arm/mach-tegra/tegra20/clock.c @@ -804,7 +804,7 @@ struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH }, - { PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ }, + { PERIPH_ID_PWM, CLOCK_ID_PERIPH }, { PERIPH_ID_DVC_I2C, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C1, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C2, CLOCK_ID_PERIPH }, diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c index 76fbfef580..900537afbe 100644 --- a/arch/arm/mach-tegra/tegra210/clock.c +++ b/arch/arm/mach-tegra/tegra210/clock.c @@ -1278,7 +1278,7 @@ struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH }, - { PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ }, + { PERIPH_ID_PWM, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C1, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C2, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C3, CLOCK_ID_PERIPH }, diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c index b66211ce94..1dc9d09dba 100644 --- a/arch/arm/mach-tegra/tegra30/clock.c +++ b/arch/arm/mach-tegra/tegra30/clock.c @@ -884,7 +884,7 @@ struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH }, - { PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ }, + { PERIPH_ID_PWM, CLOCK_ID_PERIPH }, { PERIPH_ID_DVC_I2C, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C1, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C2, CLOCK_ID_PERIPH }, diff --git a/drivers/pwm/tegra_pwm.c b/drivers/pwm/tegra_pwm.c index 36c35c608b..95fc26458b 100644 --- a/drivers/pwm/tegra_pwm.c +++ b/drivers/pwm/tegra_pwm.c @@ -20,19 +20,21 @@ static int tegra_pwm_set_config(struct udevice *dev, uint channel, { struct tegra_pwm_priv *priv = dev_get_priv(dev); struct pwm_ctlr *regs = priv->regs; + const u32 pwm_max_freq = dev_get_driver_data(dev); uint pulse_width; u32 reg; if (channel >= 4) return -EINVAL; debug("%s: Configure '%s' channel %u\n", __func__, dev->name, channel); - /* We ignore the period here and just use 32KHz */ - clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, 32768); + + clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_PERIPH, pwm_max_freq); pulse_width = duty_ns * 255 / period_ns; reg = pulse_width << PWM_WIDTH_SHIFT; reg |= 1 << PWM_DIVIDER_SHIFT; + reg |= PWM_ENABLE_MASK; writel(reg, ®s[channel].control); debug("%s: pulse_width=%u\n", __func__, pulse_width); @@ -68,8 +70,8 @@ static const struct pwm_ops tegra_pwm_ops = { }; static const struct udevice_id tegra_pwm_ids[] = { - { .compatible = "nvidia,tegra124-pwm" }, - { .compatible = "nvidia,tegra20-pwm" }, + { .compatible = "nvidia,tegra20-pwm", .data = 48 * 1000000 }, + { .compatible = "nvidia,tegra114-pwm", .data = 408 * 1000000 }, { } }; From 09ca4d802887defff2ba8ae6639703d6046136cf Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:29 +0200 Subject: [PATCH 07/16] spi: tegra20_slink: accept any word length Original t20 slink could work with commands only fully divisible by 8. This patch removes such restriction, so commands of any bitlength now can be passed and processed. Tested-by: Andreas Westman Dorcsak # ASUS TF600T T30 Tested-by: Svyatoslav Ryhel # LG P895 T30 Tested-by: Thierry Reding # T30 and T124 Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- drivers/spi/tegra20_slink.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c index 209ba8b0cc..d0e788539e 100644 --- a/drivers/spi/tegra20_slink.c +++ b/drivers/spi/tegra20_slink.c @@ -208,16 +208,14 @@ static int tegra30_spi_xfer(struct udevice *dev, unsigned int bitlen, u32 reg, tmpdout, tmpdin = 0; const u8 *dout = data_out; u8 *din = data_in; - int num_bytes; - int ret; + int num_bytes, overflow; + int ret = 0; debug("%s: slave %u:%u dout %p din %p bitlen %u\n", __func__, dev_seq(bus), spi_chip_select(dev), dout, din, bitlen); - if (bitlen % 8) - return -1; - num_bytes = bitlen / 8; - ret = 0; + num_bytes = DIV_ROUND_UP(bitlen, 8); + overflow = bitlen % 8; reg = readl(®s->status); writel(reg, ®s->status); /* Clear all SPI events via R/W */ @@ -254,8 +252,13 @@ static int tegra30_spi_xfer(struct udevice *dev, unsigned int bitlen, num_bytes -= bytes; - clrsetbits_le32(®s->command, SLINK_CMD_BIT_LENGTH_MASK, - bytes * 8 - 1); + if (overflow && !num_bytes) + clrsetbits_le32(®s->command, SLINK_CMD_BIT_LENGTH_MASK, + (bytes - 1) * 8 + overflow - 1); + else + clrsetbits_le32(®s->command, SLINK_CMD_BIT_LENGTH_MASK, + bytes * 8 - 1); + writel(tmpdout, ®s->tx_fifo); setbits_le32(®s->command, SLINK_CMD_GO); From b1de4d7c6e14a78b6f321d205daa7846badb64ae Mon Sep 17 00:00:00 2001 From: Maxim Schwalm Date: Tue, 14 Feb 2023 19:35:30 +0200 Subject: [PATCH 08/16] ARM: tegra: provide default USB gadget setup All Nvidia boards use the same manufacturer, vendor ID and product ID for the gadgets. Make them the defaults to remove some boilerplate from the defconfigs. Inspired by commit e02687bda96c ("sunxi: provide default USB gadget setup") which did the same for Allwinner boards. Tested-by: Thierry Reding # T30 and T124 Signed-off-by: Maxim Schwalm Signed-off-by: Tom --- configs/beaver_defconfig | 3 --- configs/cei-tk1-som_defconfig | 3 --- configs/dalmore_defconfig | 3 --- configs/jetson-tk1_defconfig | 3 --- configs/nyan-big_defconfig | 3 --- configs/p2371-0000_defconfig | 3 --- configs/p2371-2180_defconfig | 3 --- configs/p2571_defconfig | 3 --- configs/p3450-0000_defconfig | 3 --- configs/venice2_defconfig | 3 --- drivers/usb/gadget/Kconfig | 3 +++ 11 files changed, 3 insertions(+), 30 deletions(-) diff --git a/configs/beaver_defconfig b/configs/beaver_defconfig index 94baba45c7..0a782ad2d9 100644 --- a/configs/beaver_defconfig +++ b/configs/beaver_defconfig @@ -64,8 +64,5 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/cei-tk1-som_defconfig b/configs/cei-tk1-som_defconfig index 702f6bc20c..8d9351ea9d 100644 --- a/configs/cei-tk1-som_defconfig +++ b/configs/cei-tk1-som_defconfig @@ -70,8 +70,5 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/dalmore_defconfig b/configs/dalmore_defconfig index e5fd0d5f50..baa2632d6c 100644 --- a/configs/dalmore_defconfig +++ b/configs/dalmore_defconfig @@ -60,8 +60,5 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/jetson-tk1_defconfig b/configs/jetson-tk1_defconfig index fc5360a50c..fb1f337647 100644 --- a/configs/jetson-tk1_defconfig +++ b/configs/jetson-tk1_defconfig @@ -70,8 +70,5 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig index 6d6d8903c2..2017d5c700 100644 --- a/configs/nyan-big_defconfig +++ b/configs/nyan-big_defconfig @@ -93,9 +93,6 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_VIDEO=y diff --git a/configs/p2371-0000_defconfig b/configs/p2371-0000_defconfig index e8074914c8..2962a7db75 100644 --- a/configs/p2371-0000_defconfig +++ b/configs/p2371-0000_defconfig @@ -48,8 +48,5 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/p2371-2180_defconfig b/configs/p2371-2180_defconfig index ea62e18f73..6b44361b5b 100644 --- a/configs/p2371-2180_defconfig +++ b/configs/p2371-2180_defconfig @@ -57,8 +57,5 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/p2571_defconfig b/configs/p2571_defconfig index bc3fb3e5ae..00b0dc6109 100644 --- a/configs/p2571_defconfig +++ b/configs/p2571_defconfig @@ -49,8 +49,5 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/p3450-0000_defconfig b/configs/p3450-0000_defconfig index 8e16afde91..d35bea4220 100644 --- a/configs/p3450-0000_defconfig +++ b/configs/p3450-0000_defconfig @@ -61,8 +61,5 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/configs/venice2_defconfig b/configs/venice2_defconfig index 09fa53199a..c30bd2538c 100644 --- a/configs/venice2_defconfig +++ b/configs/venice2_defconfig @@ -59,8 +59,5 @@ CONFIG_USB_EHCI_TEGRA=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_MANUFACTURER="NVIDIA" -CONFIG_USB_GADGET_VENDOR_NUM=0x0955 -CONFIG_USB_GADGET_PRODUCT_NUM=0x701a CONFIG_CI_UDC=y CONFIG_USB_GADGET_DOWNLOAD=y diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index e120efeb00..941f97c96d 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -40,6 +40,7 @@ if USB_GADGET config USB_GADGET_MANUFACTURER string "Vendor name of the USB device" + default "NVIDIA" if ARCH_TEGRA default "Allwinner Technology" if ARCH_SUNXI default "Rockchip" if ARCH_ROCKCHIP default "U-Boot" @@ -49,6 +50,7 @@ config USB_GADGET_MANUFACTURER config USB_GADGET_VENDOR_NUM hex "Vendor ID of the USB device" + default 0x0955 if ARCH_TEGRA default 0x1f3a if ARCH_SUNXI default 0x2207 if ARCH_ROCKCHIP default 0x0 @@ -59,6 +61,7 @@ config USB_GADGET_VENDOR_NUM config USB_GADGET_PRODUCT_NUM hex "Product ID of the USB device" + default 0x701a if ARCH_TEGRA default 0x1010 if ARCH_SUNXI default 0x310a if ROCKCHIP_RK3036 default 0x300a if ROCKCHIP_RK3066 From 1a7ce63c08837bfd144a3f772d32f326c454fc86 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:31 +0200 Subject: [PATCH 09/16] ARM: tegra: add late init support Late init function allows passing values like identifiers and perform device specific configurations of pre-boot stage. Tested-by: Andreas Westman Dorcsak # ASUS TF T30 Tested-by: Svyatoslav Ryhel # LG P895 T30 Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/include/asm/arch-tegra/sys_proto.h | 6 ++++++ arch/arm/mach-tegra/board2.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/include/asm/arch-tegra/sys_proto.h b/arch/arm/include/asm/arch-tegra/sys_proto.h index c3a2673e6c..566666a9a0 100644 --- a/arch/arm/include/asm/arch-tegra/sys_proto.h +++ b/arch/arm/include/asm/arch-tegra/sys_proto.h @@ -31,4 +31,10 @@ int tegra_lcd_pmic_init(int board_id); */ int nvidia_board_init(void); +/** + * nvidia_board_late_init() - perform any board-specific + * init on late stages + */ +void nvidia_board_late_init(void); + #endif diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c index c7a45f4ff8..0df18360ca 100644 --- a/arch/arm/mach-tegra/board2.c +++ b/arch/arm/mach-tegra/board2.c @@ -56,6 +56,7 @@ __weak void gpio_early_init_uart(void) {} __weak void pin_mux_display(void) {} __weak void start_cpu_fan(void) {} __weak void cboot_late_init(void) {} +__weak void nvidia_board_late_init(void) {} #if defined(CONFIG_TEGRA_NAND) __weak void pin_mux_nand(void) @@ -267,6 +268,7 @@ int board_late_init(void) #endif start_cpu_fan(); cboot_late_init(); + nvidia_board_late_init(); return 0; } From 4213d52b332e9fad41a199f022fbc104d6b2d946 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:32 +0200 Subject: [PATCH 10/16] ARM: tegra: create common pre-dm i2c write This implementation allows pwr i2c writing on early SPL stages when DM is not yet setup. Such writing is needed to configure main voltages of PMIC on early SPL for bootloader to boot properly. Tested-by: Andreas Westman Dorcsak # ASUS TF T30 Tested-by: Robert Eckelmann # ASUS TF101 T20 Tested-by: Svyatoslav Ryhel # LG P895 T30 Tested-by: Thierry Reding # T30 and T124 Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/include/asm/arch-tegra/tegra_i2c.h | 17 ++++++++++ arch/arm/mach-tegra/cpu.h | 1 - arch/arm/mach-tegra/tegra124/cpu.c | 4 +++ arch/arm/mach-tegra/tegra30/cpu.c | 37 +++++++-------------- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/arch/arm/include/asm/arch-tegra/tegra_i2c.h b/arch/arm/include/asm/arch-tegra/tegra_i2c.h index c49f43251d..afec6bbdda 100644 --- a/arch/arm/include/asm/arch-tegra/tegra_i2c.h +++ b/arch/arm/include/asm/arch-tegra/tegra_i2c.h @@ -8,6 +8,7 @@ #ifndef _TEGRA_I2C_H_ #define _TEGRA_I2C_H_ +#include #include struct udevice; @@ -154,4 +155,20 @@ struct i2c_ctlr { */ int tegra_i2c_get_dvc_bus(struct udevice **busp); +/* Pre-dm section used for initial setup of PMIC */ +#define I2C_SEND_2_BYTES 0x0A02 + +static inline void tegra_i2c_ll_write(uint addr, uint data) +{ + struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE; + + writel(addr, ®->cmd_addr0); + writel(0x2, ®->cnfg); + + writel(data, ®->cmd_data1); + writel(I2C_SEND_2_BYTES, ®->cnfg); +} + +void pmic_enable_cpu_vdd(void); + #endif /* _TEGRA_I2C_H_ */ diff --git a/arch/arm/mach-tegra/cpu.h b/arch/arm/mach-tegra/cpu.h index d541825441..006aae3d07 100644 --- a/arch/arm/mach-tegra/cpu.h +++ b/arch/arm/mach-tegra/cpu.h @@ -74,4 +74,3 @@ int tegra_get_chip(void); int tegra_get_sku_info(void); int tegra_get_chip_sku(void); void adjust_pllp_out_freqs(void); -void pmic_enable_cpu_vdd(void); diff --git a/arch/arm/mach-tegra/tegra124/cpu.c b/arch/arm/mach-tegra/tegra124/cpu.c index d5f2683b26..b1bfe8fb5e 100644 --- a/arch/arm/mach-tegra/tegra124/cpu.c +++ b/arch/arm/mach-tegra/tegra124/cpu.c @@ -14,10 +14,14 @@ #include #include #include +#include #include #include #include "../cpu.h" +/* In case this function is not defined */ +__weak void pmic_enable_cpu_vdd(void) {} + /* Tegra124-specific CPU init code */ static void enable_cpu_power_rail(void) diff --git a/arch/arm/mach-tegra/tegra30/cpu.c b/arch/arm/mach-tegra/tegra30/cpu.c index 651edd27ee..6ac45af51a 100644 --- a/arch/arm/mach-tegra/tegra30/cpu.c +++ b/arch/arm/mach-tegra/tegra30/cpu.c @@ -15,23 +15,6 @@ #include #include "../cpu.h" -/* Tegra30-specific CPU init code */ -void tegra_i2c_ll_write_addr(uint addr, uint config) -{ - struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE; - - writel(addr, ®->cmd_addr0); - writel(config, ®->cnfg); -} - -void tegra_i2c_ll_write_data(uint data, uint config) -{ - struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE; - - writel(data, ®->cmd_data1); - writel(config, ®->cnfg); -} - #define TPS62366A_I2C_ADDR 0xC0 #define TPS62366A_SET1_REG 0x01 #define TPS62366A_SET1_DATA (0x4600 | TPS62366A_SET1_REG) @@ -45,7 +28,9 @@ void tegra_i2c_ll_write_data(uint data, uint config) #define TPS65911_VDDCTRL_SR_REG 0x27 #define TPS65911_VDDCTRL_OP_DATA (0x2400 | TPS65911_VDDCTRL_OP_REG) #define TPS65911_VDDCTRL_SR_DATA (0x0100 | TPS65911_VDDCTRL_SR_REG) -#define I2C_SEND_2_BYTES 0x0A02 + +/* In case this function is not defined */ +__weak void pmic_enable_cpu_vdd(void) {} static void enable_cpu_power_rail(void) { @@ -59,12 +44,12 @@ static void enable_cpu_power_rail(void) /* Set VDD_CORE to 1.200V. */ #ifdef CONFIG_TEGRA_VDD_CORE_TPS62366A_SET1 - tegra_i2c_ll_write_addr(TPS62366A_I2C_ADDR, 2); - tegra_i2c_ll_write_data(TPS62366A_SET1_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(TPS62366A_I2C_ADDR, + TPS62366A_SET1_DATA); #endif #ifdef CONFIG_TEGRA_VDD_CORE_TPS62361B_SET3 - tegra_i2c_ll_write_addr(TPS62361B_I2C_ADDR, 2); - tegra_i2c_ll_write_data(TPS62361B_SET3_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(TPS62361B_I2C_ADDR, + TPS62361B_SET3_DATA); #endif udelay(1000); @@ -72,10 +57,11 @@ static void enable_cpu_power_rail(void) * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus. * First set VDD to 1.0125V, then enable the VDD regulator. */ - tegra_i2c_ll_write_addr(TPS65911_I2C_ADDR, 2); - tegra_i2c_ll_write_data(TPS65911_VDDCTRL_OP_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_OP_DATA); udelay(1000); - tegra_i2c_ll_write_data(TPS65911_VDDCTRL_SR_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_SR_DATA); udelay(10 * 1000); } @@ -142,6 +128,7 @@ void start_cpu(u32 reset_vector) /* Enable VDD_CPU */ enable_cpu_power_rail(); + pmic_enable_cpu_vdd(); set_cpu_running(0); From e7184debf4c2f35518811990473103793a1f639d Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:33 +0200 Subject: [PATCH 11/16] board: tegra124: switch to updated pre-dm i2c write Configure PMIC for early stages using updated i2c write. Tested-by: Thierry Reding # Jetson TK1 T124 Signed-off-by: Svyatoslav Ryhel Reviewed-by: Simon Glass Signed-off-by: Tom --- board/nvidia/venice2/as3722_init.c | 71 ++++++++++++-------- board/nvidia/venice2/as3722_init.h | 43 ------------ board/toradex/apalis-tk1/as3722_init.c | 91 ++++++++++++++------------ board/toradex/apalis-tk1/as3722_init.h | 40 ----------- 4 files changed, 94 insertions(+), 151 deletions(-) delete mode 100644 board/nvidia/venice2/as3722_init.h delete mode 100644 board/toradex/apalis-tk1/as3722_init.h diff --git a/board/nvidia/venice2/as3722_init.c b/board/nvidia/venice2/as3722_init.c index ba676547d3..395bdd99c7 100644 --- a/board/nvidia/venice2/as3722_init.c +++ b/board/nvidia/venice2/as3722_init.c @@ -9,26 +9,43 @@ #include #include #include -#include "as3722_init.h" + +/* AS3722-PMIC-specific early init regs */ + +#define AS3722_I2C_ADDR 0x80 + +#define AS3722_SD0VOLTAGE_REG 0x00 /* CPU */ +#define AS3722_SD1VOLTAGE_REG 0x01 /* CORE, already set by OTP */ +#define AS3722_SD6VOLTAGE_REG 0x06 /* GPU */ +#define AS3722_SDCONTROL_REG 0x4D + +#define AS3722_LDO2VOLTAGE_REG 0x12 /* VPP_FUSE */ +#define AS3722_LDO6VOLTAGE_REG 0x16 /* VDD_SDMMC */ +#define AS3722_LDCONTROL_REG 0x4E + +#if defined(CONFIG_TARGET_VENICE2) +#define AS3722_SD0VOLTAGE_DATA (0x2800 | AS3722_SD0VOLTAGE_REG) +#else /* TK1 or Nyan-Big */ +#define AS3722_SD0VOLTAGE_DATA (0x3C00 | AS3722_SD0VOLTAGE_REG) +#endif +#define AS3722_SD0CONTROL_DATA (0x0100 | AS3722_SDCONTROL_REG) + +#if defined(CONFIG_TARGET_JETSON_TK1) || defined(CONFIG_TARGET_CEI_TK1_SOM) +#define AS3722_SD1VOLTAGE_DATA (0x2800 | AS3722_SD1VOLTAGE_REG) +#define AS3722_SD1CONTROL_DATA (0x0200 | AS3722_SDCONTROL_REG) +#endif + +#define AS3722_SD6CONTROL_DATA (0x4000 | AS3722_SDCONTROL_REG) +#define AS3722_SD6VOLTAGE_DATA (0x2800 | AS3722_SD6VOLTAGE_REG) + +#define AS3722_LDO2CONTROL_DATA (0x0400 | AS3722_LDCONTROL_REG) +#define AS3722_LDO2VOLTAGE_DATA (0x1000 | AS3722_LDO2VOLTAGE_REG) + +#define AS3722_LDO6CONTROL_DATA (0x4000 | AS3722_LDCONTROL_REG) +#define AS3722_LDO6VOLTAGE_DATA (0x3F00 | AS3722_LDO6VOLTAGE_REG) /* AS3722-PMIC-specific early init code - get CPU rails up, etc */ -void tegra_i2c_ll_write_addr(uint addr, uint config) -{ - struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE; - - writel(addr, ®->cmd_addr0); - writel(config, ®->cnfg); -} - -void tegra_i2c_ll_write_data(uint data, uint config) -{ - struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE; - - writel(data, ®->cmd_data1); - writel(config, ®->cnfg); -} - void pmic_enable_cpu_vdd(void) { debug("%s entry\n", __func__); @@ -37,8 +54,8 @@ void pmic_enable_cpu_vdd(void) /* Set up VDD_CORE, for boards where OTP is incorrect*/ debug("%s: Setting VDD_CORE via AS3722 reg 1\n", __func__); /* Configure VDD_CORE via the AS3722 PMIC on the PWR I2C bus */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_SD1VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_SD1VOLTAGE_DATA); /* * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled. * tegra_i2c_ll_write_data(AS3722_SD1CONTROL_DATA, I2C_SEND_2_BYTES); @@ -51,8 +68,8 @@ void pmic_enable_cpu_vdd(void) * Bring up VDD_CPU via the AS3722 PMIC on the PWR I2C bus. * First set VDD to 1.0V, then enable the VDD regulator. */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_SD0VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_SD0VOLTAGE_DATA); /* * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled. * tegra_i2c_ll_write_data(AS3722_SD0CONTROL_DATA, I2C_SEND_2_BYTES); @@ -64,8 +81,8 @@ void pmic_enable_cpu_vdd(void) * Bring up VDD_GPU via the AS3722 PMIC on the PWR I2C bus. * First set VDD to 1.0V, then enable the VDD regulator. */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_SD6VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_SD6VOLTAGE_DATA); /* * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled. * tegra_i2c_ll_write_data(AS3722_SD6CONTROL_DATA, I2C_SEND_2_BYTES); @@ -77,8 +94,8 @@ void pmic_enable_cpu_vdd(void) * Bring up VPP_FUSE via the AS3722 PMIC on the PWR I2C bus. * First set VDD to 1.2V, then enable the VDD regulator. */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_LDO2VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_LDO2VOLTAGE_DATA); /* * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled. * tegra_i2c_ll_write_data(AS3722_LDO2CONTROL_DATA, I2C_SEND_2_BYTES); @@ -93,8 +110,8 @@ void pmic_enable_cpu_vdd(void) * NOTE: We do this early because doing it later seems to hose the CPU * power rail/partition startup. Need to debug. */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_LDO6VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_LDO6VOLTAGE_DATA); /* * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled. * tegra_i2c_ll_write_data(AS3722_LDO6CONTROL_DATA, I2C_SEND_2_BYTES); diff --git a/board/nvidia/venice2/as3722_init.h b/board/nvidia/venice2/as3722_init.h deleted file mode 100644 index 17e7d76ae7..0000000000 --- a/board/nvidia/venice2/as3722_init.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * (C) Copyright 2013 - * NVIDIA Corporation - */ - -/* AS3722-PMIC-specific early init regs */ - -#define AS3722_I2C_ADDR 0x80 - -#define AS3722_SD0VOLTAGE_REG 0x00 /* CPU */ -#define AS3722_SD1VOLTAGE_REG 0x01 /* CORE, already set by OTP */ -#define AS3722_SD6VOLTAGE_REG 0x06 /* GPU */ -#define AS3722_SDCONTROL_REG 0x4D - -#define AS3722_LDO2VOLTAGE_REG 0x12 /* VPP_FUSE */ -#define AS3722_LDO6VOLTAGE_REG 0x16 /* VDD_SDMMC */ -#define AS3722_LDCONTROL_REG 0x4E - -#if defined(CONFIG_TARGET_VENICE2) -#define AS3722_SD0VOLTAGE_DATA (0x2800 | AS3722_SD0VOLTAGE_REG) -#else /* TK1 or Nyan-Big */ -#define AS3722_SD0VOLTAGE_DATA (0x3C00 | AS3722_SD0VOLTAGE_REG) -#endif -#define AS3722_SD0CONTROL_DATA (0x0100 | AS3722_SDCONTROL_REG) - -#if defined(CONFIG_TARGET_JETSON_TK1) || defined(CONFIG_TARGET_CEI_TK1_SOM) -#define AS3722_SD1VOLTAGE_DATA (0x2800 | AS3722_SD1VOLTAGE_REG) -#define AS3722_SD1CONTROL_DATA (0x0200 | AS3722_SDCONTROL_REG) -#endif - -#define AS3722_SD6CONTROL_DATA (0x4000 | AS3722_SDCONTROL_REG) -#define AS3722_SD6VOLTAGE_DATA (0x2800 | AS3722_SD6VOLTAGE_REG) - -#define AS3722_LDO2CONTROL_DATA (0x0400 | AS3722_LDCONTROL_REG) -#define AS3722_LDO2VOLTAGE_DATA (0x1000 | AS3722_LDO2VOLTAGE_REG) - -#define AS3722_LDO6CONTROL_DATA (0x4000 | AS3722_LDCONTROL_REG) -#define AS3722_LDO6VOLTAGE_DATA (0x3F00 | AS3722_LDO6VOLTAGE_REG) - -#define I2C_SEND_2_BYTES 0x0A02 - -void pmic_enable_cpu_vdd(void); diff --git a/board/toradex/apalis-tk1/as3722_init.c b/board/toradex/apalis-tk1/as3722_init.c index 68169f5548..e9bd1028be 100644 --- a/board/toradex/apalis-tk1/as3722_init.c +++ b/board/toradex/apalis-tk1/as3722_init.c @@ -8,26 +8,41 @@ #include #include #include -#include "as3722_init.h" + +/* AS3722-PMIC-specific early init regs */ + +#define AS3722_I2C_ADDR 0x80 + +#define AS3722_SD0VOLTAGE_REG 0x00 /* CPU */ +#define AS3722_SD1VOLTAGE_REG 0x01 /* CORE, already set by OTP */ +#define AS3722_SD6VOLTAGE_REG 0x06 /* GPU */ +#define AS3722_SDCONTROL_REG 0x4D + +#define AS3722_LDO1VOLTAGE_REG 0x11 /* VDD_SDMMC1 */ +#define AS3722_LDO2VOLTAGE_REG 0x12 /* VPP_FUSE */ +#define AS3722_LDO6VOLTAGE_REG 0x16 /* VDD_SDMMC3 */ +#define AS3722_LDCONTROL_REG 0x4E + +#define AS3722_SD0VOLTAGE_DATA (0x3C00 | AS3722_SD0VOLTAGE_REG) +#define AS3722_SD0CONTROL_DATA (0x0100 | AS3722_SDCONTROL_REG) + +#define AS3722_SD1VOLTAGE_DATA (0x3200 | AS3722_SD1VOLTAGE_REG) +#define AS3722_SD1CONTROL_DATA (0x0200 | AS3722_SDCONTROL_REG) + +#define AS3722_SD6CONTROL_DATA (0x4000 | AS3722_SDCONTROL_REG) +#define AS3722_SD6VOLTAGE_DATA (0x2800 | AS3722_SD6VOLTAGE_REG) + +#define AS3722_LDO1CONTROL_DATA (0x0200 | AS3722_LDCONTROL_REG) +#define AS3722_LDO1VOLTAGE_DATA (0x7F00 | AS3722_LDO1VOLTAGE_REG) + +#define AS3722_LDO2CONTROL_DATA (0x0400 | AS3722_LDCONTROL_REG) +#define AS3722_LDO2VOLTAGE_DATA (0x1000 | AS3722_LDO2VOLTAGE_REG) + +#define AS3722_LDO6CONTROL_DATA (0x4000 | AS3722_LDCONTROL_REG) +#define AS3722_LDO6VOLTAGE_DATA (0x3F00 | AS3722_LDO6VOLTAGE_REG) /* AS3722-PMIC-specific early init code - get CPU rails up, etc */ -void tegra_i2c_ll_write_addr(uint addr, uint config) -{ - struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE; - - writel(addr, ®->cmd_addr0); - writel(config, ®->cnfg); -} - -void tegra_i2c_ll_write_data(uint data, uint config) -{ - struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE; - - writel(data, ®->cmd_data1); - writel(config, ®->cnfg); -} - void pmic_enable_cpu_vdd(void) { debug("%s entry\n", __func__); @@ -36,8 +51,8 @@ void pmic_enable_cpu_vdd(void) /* Set up VDD_CORE, for boards where OTP is incorrect*/ debug("%s: Setting VDD_CORE via AS3722 reg 1\n", __func__); /* Configure VDD_CORE via the AS3722 PMIC on the PWR I2C bus */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_SD1VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_SD1VOLTAGE_DATA); /* * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled. * tegra_i2c_ll_write_data(AS3722_SD1CONTROL_DATA, I2C_SEND_2_BYTES); @@ -49,23 +64,17 @@ void pmic_enable_cpu_vdd(void) * Make sure all non-fused regulators are down. * That way we're in known state after software reboot from linux */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(0x0003, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x0003); udelay(10 * 1000); - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(0x0004, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x0004); udelay(10 * 1000); - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(0x001b, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x001b); udelay(10 * 1000); - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(0x0014, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x0014); udelay(10 * 1000); - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(0x001a, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x001a); udelay(10 * 1000); - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(0x0019, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, 0x0019); udelay(10 * 1000); debug("%s: Setting VDD_CPU to 1.0V via AS3722 reg 0/4D\n", __func__); @@ -73,8 +82,8 @@ void pmic_enable_cpu_vdd(void) * Bring up VDD_CPU via the AS3722 PMIC on the PWR I2C bus. * First set VDD to 1.0V, then enable the VDD regulator. */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_SD0VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_SD0VOLTAGE_DATA); /* * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled. * tegra_i2c_ll_write_data(AS3722_SD0CONTROL_DATA, I2C_SEND_2_BYTES); @@ -86,8 +95,8 @@ void pmic_enable_cpu_vdd(void) * Bring up VDD_GPU via the AS3722 PMIC on the PWR I2C bus. * First set VDD to 1.0V, then enable the VDD regulator. */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_SD6VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_SD6VOLTAGE_DATA); /* * Don't write SDCONTROL - it's already 0x7F, i.e. all SDs enabled. * tegra_i2c_ll_write_data(AS3722_SD6CONTROL_DATA, I2C_SEND_2_BYTES); @@ -99,8 +108,8 @@ void pmic_enable_cpu_vdd(void) * Bring up VPP_FUSE via the AS3722 PMIC on the PWR I2C bus. * First set VDD to 1.2V, then enable the VDD regulator. */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_LDO2VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_LDO2VOLTAGE_DATA); /* * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled. * tegra_i2c_ll_write_data(AS3722_LDO2CONTROL_DATA, I2C_SEND_2_BYTES); @@ -115,8 +124,8 @@ void pmic_enable_cpu_vdd(void) * NOTE: We do this early because doing it later seems to hose the CPU * power rail/partition startup. Need to debug. */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_LDO1VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_LDO1VOLTAGE_DATA); /* * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled. * tegra_i2c_ll_write_data(AS3722_LDO1CONTROL_DATA, I2C_SEND_2_BYTES); @@ -131,8 +140,8 @@ void pmic_enable_cpu_vdd(void) * NOTE: We do this early because doing it later seems to hose the CPU * power rail/partition startup. Need to debug. */ - tegra_i2c_ll_write_addr(AS3722_I2C_ADDR, 2); - tegra_i2c_ll_write_data(AS3722_LDO6VOLTAGE_DATA, I2C_SEND_2_BYTES); + tegra_i2c_ll_write(AS3722_I2C_ADDR, + AS3722_LDO6VOLTAGE_DATA); /* * Don't write LDCONTROL - it's already 0xFF, i.e. all LDOs enabled. * tegra_i2c_ll_write_data(AS3722_LDO6CONTROL_DATA, I2C_SEND_2_BYTES); diff --git a/board/toradex/apalis-tk1/as3722_init.h b/board/toradex/apalis-tk1/as3722_init.h deleted file mode 100644 index 99836de966..0000000000 --- a/board/toradex/apalis-tk1/as3722_init.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2012-2016 Toradex, Inc. - */ - -/* AS3722-PMIC-specific early init regs */ - -#define AS3722_I2C_ADDR 0x80 - -#define AS3722_SD0VOLTAGE_REG 0x00 /* CPU */ -#define AS3722_SD1VOLTAGE_REG 0x01 /* CORE, already set by OTP */ -#define AS3722_SD6VOLTAGE_REG 0x06 /* GPU */ -#define AS3722_SDCONTROL_REG 0x4D - -#define AS3722_LDO1VOLTAGE_REG 0x11 /* VDD_SDMMC1 */ -#define AS3722_LDO2VOLTAGE_REG 0x12 /* VPP_FUSE */ -#define AS3722_LDO6VOLTAGE_REG 0x16 /* VDD_SDMMC3 */ -#define AS3722_LDCONTROL_REG 0x4E - -#define AS3722_SD0VOLTAGE_DATA (0x3C00 | AS3722_SD0VOLTAGE_REG) -#define AS3722_SD0CONTROL_DATA (0x0100 | AS3722_SDCONTROL_REG) - -#define AS3722_SD1VOLTAGE_DATA (0x3200 | AS3722_SD1VOLTAGE_REG) -#define AS3722_SD1CONTROL_DATA (0x0200 | AS3722_SDCONTROL_REG) - -#define AS3722_SD6CONTROL_DATA (0x4000 | AS3722_SDCONTROL_REG) -#define AS3722_SD6VOLTAGE_DATA (0x2800 | AS3722_SD6VOLTAGE_REG) - -#define AS3722_LDO1CONTROL_DATA (0x0200 | AS3722_LDCONTROL_REG) -#define AS3722_LDO1VOLTAGE_DATA (0x7F00 | AS3722_LDO1VOLTAGE_REG) - -#define AS3722_LDO2CONTROL_DATA (0x0400 | AS3722_LDCONTROL_REG) -#define AS3722_LDO2VOLTAGE_DATA (0x1000 | AS3722_LDO2VOLTAGE_REG) - -#define AS3722_LDO6CONTROL_DATA (0x4000 | AS3722_LDCONTROL_REG) -#define AS3722_LDO6VOLTAGE_DATA (0x3F00 | AS3722_LDO6VOLTAGE_REG) - -#define I2C_SEND_2_BYTES 0x0A02 - -void pmic_enable_cpu_vdd(void); From 5668c75ce97d9209d4a0d193b16791a100cc99a8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:34 +0200 Subject: [PATCH 12/16] board: tegra30: switch to updated pre-dm i2c write Configure PMIC voltages for early stages using updated early i2c write. Tested-by: Thierry Reding # Beaver T30 Signed-off-by: Svyatoslav Ryhel Reviewed-by: Simon Glass Signed-off-by: Tom --- arch/arm/mach-tegra/tegra30/Kconfig | 8 ---- arch/arm/mach-tegra/tegra30/cpu.c | 36 ----------------- board/avionic-design/tec-ng/Makefile | 4 +- board/avionic-design/tec-ng/tec-ng-spl.c | 34 ++++++++++++++++ board/nvidia/beaver/Makefile | 2 + board/nvidia/beaver/beaver-spl.c | 43 +++++++++++++++++++++ board/nvidia/cardhu/Makefile | 4 +- board/nvidia/cardhu/cardhu-spl.c | 43 +++++++++++++++++++++ board/toradex/apalis_t30/Makefile | 2 + board/toradex/apalis_t30/apalis_t30-spl.c | 34 ++++++++++++++++ board/toradex/colibri_t30/Makefile | 2 + board/toradex/colibri_t30/colibri_t30-spl.c | 34 ++++++++++++++++ 12 files changed, 200 insertions(+), 46 deletions(-) create mode 100644 board/avionic-design/tec-ng/tec-ng-spl.c create mode 100644 board/nvidia/beaver/beaver-spl.c create mode 100644 board/nvidia/cardhu/cardhu-spl.c create mode 100644 board/toradex/apalis_t30/apalis_t30-spl.c create mode 100644 board/toradex/colibri_t30/colibri_t30-spl.c diff --git a/arch/arm/mach-tegra/tegra30/Kconfig b/arch/arm/mach-tegra/tegra30/Kconfig index 5619d1cd42..85b8ce294f 100644 --- a/arch/arm/mach-tegra/tegra30/Kconfig +++ b/arch/arm/mach-tegra/tegra30/Kconfig @@ -1,11 +1,5 @@ if TEGRA30 -config TEGRA_VDD_CORE_TPS62361B_SET3 - bool - -config TEGRA_VDD_CORE_TPS62366A_SET1 - bool - choice prompt "Tegra30 board select" optional @@ -17,12 +11,10 @@ config TARGET_APALIS_T30 config TARGET_BEAVER bool "NVIDIA Tegra30 Beaver evaluation board" select BOARD_LATE_INIT - select TEGRA_VDD_CORE_TPS62366A_SET1 config TARGET_CARDHU bool "NVIDIA Tegra30 Cardhu evaluation board" select BOARD_LATE_INIT - select TEGRA_VDD_CORE_TPS62361B_SET3 config TARGET_COLIBRI_T30 bool "Toradex Colibri T30 board" diff --git a/arch/arm/mach-tegra/tegra30/cpu.c b/arch/arm/mach-tegra/tegra30/cpu.c index 6ac45af51a..60bbf13ea5 100644 --- a/arch/arm/mach-tegra/tegra30/cpu.c +++ b/arch/arm/mach-tegra/tegra30/cpu.c @@ -15,20 +15,6 @@ #include #include "../cpu.h" -#define TPS62366A_I2C_ADDR 0xC0 -#define TPS62366A_SET1_REG 0x01 -#define TPS62366A_SET1_DATA (0x4600 | TPS62366A_SET1_REG) - -#define TPS62361B_I2C_ADDR 0xC0 -#define TPS62361B_SET3_REG 0x03 -#define TPS62361B_SET3_DATA (0x4600 | TPS62361B_SET3_REG) - -#define TPS65911_I2C_ADDR 0x5A -#define TPS65911_VDDCTRL_OP_REG 0x28 -#define TPS65911_VDDCTRL_SR_REG 0x27 -#define TPS65911_VDDCTRL_OP_DATA (0x2400 | TPS65911_VDDCTRL_OP_REG) -#define TPS65911_VDDCTRL_SR_DATA (0x0100 | TPS65911_VDDCTRL_SR_REG) - /* In case this function is not defined */ __weak void pmic_enable_cpu_vdd(void) {} @@ -41,28 +27,6 @@ static void enable_cpu_power_rail(void) reg = readl(&pmc->pmc_cntrl); reg |= CPUPWRREQ_OE; writel(reg, &pmc->pmc_cntrl); - - /* Set VDD_CORE to 1.200V. */ -#ifdef CONFIG_TEGRA_VDD_CORE_TPS62366A_SET1 - tegra_i2c_ll_write(TPS62366A_I2C_ADDR, - TPS62366A_SET1_DATA); -#endif -#ifdef CONFIG_TEGRA_VDD_CORE_TPS62361B_SET3 - tegra_i2c_ll_write(TPS62361B_I2C_ADDR, - TPS62361B_SET3_DATA); -#endif - udelay(1000); - - /* - * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus. - * First set VDD to 1.0125V, then enable the VDD regulator. - */ - tegra_i2c_ll_write(TPS65911_I2C_ADDR, - TPS65911_VDDCTRL_OP_DATA); - udelay(1000); - tegra_i2c_ll_write(TPS65911_I2C_ADDR, - TPS65911_VDDCTRL_SR_DATA); - udelay(10 * 1000); } /** diff --git a/board/avionic-design/tec-ng/Makefile b/board/avionic-design/tec-ng/Makefile index 46df14d991..d6890e5797 100644 --- a/board/avionic-design/tec-ng/Makefile +++ b/board/avionic-design/tec-ng/Makefile @@ -3,4 +3,6 @@ # (C) Copyright 2013 # Avionic Design GmbH -obj-y := ../common/tamonten-ng.o +obj-$(CONFIG_SPL_BUILD) += tec-ng-spl.o + +obj-y += ../common/tamonten-ng.o diff --git a/board/avionic-design/tec-ng/tec-ng-spl.c b/board/avionic-design/tec-ng/tec-ng-spl.c new file mode 100644 index 0000000000..6e54464183 --- /dev/null +++ b/board/avionic-design/tec-ng/tec-ng-spl.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * (C) Copyright 2010-2013 + * NVIDIA Corporation + * + * (C) Copyright 2021 + * Svyatoslav Ryhel + */ + +#include +#include +#include + +/* I2C addr is in 8 bit */ +#define TPS65911_I2C_ADDR 0x5A +#define TPS65911_VDDCTRL_OP_REG 0x28 +#define TPS65911_VDDCTRL_SR_REG 0x27 +#define TPS65911_VDDCTRL_OP_DATA (0x2400 | TPS65911_VDDCTRL_OP_REG) +#define TPS65911_VDDCTRL_SR_DATA (0x0100 | TPS65911_VDDCTRL_SR_REG) + +void pmic_enable_cpu_vdd(void) +{ + /* + * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus. + * First set VDD to 1.0125V, then enable the VDD regulator. + */ + udelay(1000); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_OP_DATA); + udelay(1000); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_SR_DATA); + udelay(10 * 1000); +} diff --git a/board/nvidia/beaver/Makefile b/board/nvidia/beaver/Makefile index 80cff3eb9c..5e9e70825c 100644 --- a/board/nvidia/beaver/Makefile +++ b/board/nvidia/beaver/Makefile @@ -2,4 +2,6 @@ # # Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. +obj-$(CONFIG_SPL_BUILD) += beaver-spl.o + obj-y = ../cardhu/cardhu.o diff --git a/board/nvidia/beaver/beaver-spl.c b/board/nvidia/beaver/beaver-spl.c new file mode 100644 index 0000000000..b5d0c14854 --- /dev/null +++ b/board/nvidia/beaver/beaver-spl.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * (C) Copyright 2010-2013 + * NVIDIA Corporation + * + * (C) Copyright 2021 + * Svyatoslav Ryhel + */ + +#include +#include +#include + +/* I2C addr is in 8 bit */ +#define TPS65911_I2C_ADDR 0x5A +#define TPS65911_VDDCTRL_OP_REG 0x28 +#define TPS65911_VDDCTRL_SR_REG 0x27 +#define TPS65911_VDDCTRL_OP_DATA (0x2400 | TPS65911_VDDCTRL_OP_REG) +#define TPS65911_VDDCTRL_SR_DATA (0x0100 | TPS65911_VDDCTRL_SR_REG) + +#define TPS62366A_I2C_ADDR 0xC0 +#define TPS62366A_SET1_REG 0x01 +#define TPS62366A_SET1_DATA (0x4600 | TPS62366A_SET1_REG) + +void pmic_enable_cpu_vdd(void) +{ + /* Set VDD_CORE to 1.200V. */ + tegra_i2c_ll_write(TPS62366A_I2C_ADDR, + TPS62366A_SET1_DATA); + + udelay(1000); + + /* + * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus. + * First set VDD to 1.0125V, then enable the VDD regulator. + */ + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_OP_DATA); + udelay(1000); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_SR_DATA); + udelay(10 * 1000); +} diff --git a/board/nvidia/cardhu/Makefile b/board/nvidia/cardhu/Makefile index 95971053d9..6f480cdfd3 100644 --- a/board/nvidia/cardhu/Makefile +++ b/board/nvidia/cardhu/Makefile @@ -3,4 +3,6 @@ # (C) Copyright 2010-2012 # NVIDIA Corporation -obj-y := cardhu.o +obj-$(CONFIG_SPL_BUILD) += cardhu-spl.o + +obj-y += cardhu.o diff --git a/board/nvidia/cardhu/cardhu-spl.c b/board/nvidia/cardhu/cardhu-spl.c new file mode 100644 index 0000000000..de2fa300f1 --- /dev/null +++ b/board/nvidia/cardhu/cardhu-spl.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * (C) Copyright 2010-2013 + * NVIDIA Corporation + * + * (C) Copyright 2021 + * Svyatoslav Ryhel + */ + +#include +#include +#include + +/* I2C addr is in 8 bit */ +#define TPS65911_I2C_ADDR 0x5A +#define TPS65911_VDDCTRL_OP_REG 0x28 +#define TPS65911_VDDCTRL_SR_REG 0x27 +#define TPS65911_VDDCTRL_OP_DATA (0x2400 | TPS65911_VDDCTRL_OP_REG) +#define TPS65911_VDDCTRL_SR_DATA (0x0100 | TPS65911_VDDCTRL_SR_REG) + +#define TPS62361B_I2C_ADDR 0xC0 +#define TPS62361B_SET3_REG 0x03 +#define TPS62361B_SET3_DATA (0x4600 | TPS62361B_SET3_REG) + +void pmic_enable_cpu_vdd(void) +{ + /* Set VDD_CORE to 1.200V. */ + tegra_i2c_ll_write(TPS62361B_I2C_ADDR, + TPS62361B_SET3_DATA); + + udelay(1000); + + /* + * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus. + * First set VDD to 1.0125V, then enable the VDD regulator. + */ + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_OP_DATA); + udelay(1000); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_SR_DATA); + udelay(10 * 1000); +} diff --git a/board/toradex/apalis_t30/Makefile b/board/toradex/apalis_t30/Makefile index 0ea3d8f217..eed607043f 100644 --- a/board/toradex/apalis_t30/Makefile +++ b/board/toradex/apalis_t30/Makefile @@ -1,4 +1,6 @@ # Copyright (c) 2014 Marcel Ziswiler # SPDX-License-Identifier: GPL-2.0+ +obj-$(CONFIG_SPL_BUILD) += apalis_t30-spl.o + obj-y += apalis_t30.o diff --git a/board/toradex/apalis_t30/apalis_t30-spl.c b/board/toradex/apalis_t30/apalis_t30-spl.c new file mode 100644 index 0000000000..6e54464183 --- /dev/null +++ b/board/toradex/apalis_t30/apalis_t30-spl.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * (C) Copyright 2010-2013 + * NVIDIA Corporation + * + * (C) Copyright 2021 + * Svyatoslav Ryhel + */ + +#include +#include +#include + +/* I2C addr is in 8 bit */ +#define TPS65911_I2C_ADDR 0x5A +#define TPS65911_VDDCTRL_OP_REG 0x28 +#define TPS65911_VDDCTRL_SR_REG 0x27 +#define TPS65911_VDDCTRL_OP_DATA (0x2400 | TPS65911_VDDCTRL_OP_REG) +#define TPS65911_VDDCTRL_SR_DATA (0x0100 | TPS65911_VDDCTRL_SR_REG) + +void pmic_enable_cpu_vdd(void) +{ + /* + * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus. + * First set VDD to 1.0125V, then enable the VDD regulator. + */ + udelay(1000); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_OP_DATA); + udelay(1000); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_SR_DATA); + udelay(10 * 1000); +} diff --git a/board/toradex/colibri_t30/Makefile b/board/toradex/colibri_t30/Makefile index 4242902dae..8f333235b1 100644 --- a/board/toradex/colibri_t30/Makefile +++ b/board/toradex/colibri_t30/Makefile @@ -1,4 +1,6 @@ # Copyright (c) 2013-2014 Stefan Agner # SPDX-License-Identifier: GPL-2.0+ +obj-$(CONFIG_SPL_BUILD) += colibri_t30-spl.o + obj-y += colibri_t30.o diff --git a/board/toradex/colibri_t30/colibri_t30-spl.c b/board/toradex/colibri_t30/colibri_t30-spl.c new file mode 100644 index 0000000000..6e54464183 --- /dev/null +++ b/board/toradex/colibri_t30/colibri_t30-spl.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * (C) Copyright 2010-2013 + * NVIDIA Corporation + * + * (C) Copyright 2021 + * Svyatoslav Ryhel + */ + +#include +#include +#include + +/* I2C addr is in 8 bit */ +#define TPS65911_I2C_ADDR 0x5A +#define TPS65911_VDDCTRL_OP_REG 0x28 +#define TPS65911_VDDCTRL_SR_REG 0x27 +#define TPS65911_VDDCTRL_OP_DATA (0x2400 | TPS65911_VDDCTRL_OP_REG) +#define TPS65911_VDDCTRL_SR_DATA (0x0100 | TPS65911_VDDCTRL_SR_REG) + +void pmic_enable_cpu_vdd(void) +{ + /* + * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus. + * First set VDD to 1.0125V, then enable the VDD regulator. + */ + udelay(1000); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_OP_DATA); + udelay(1000); + tegra_i2c_ll_write(TPS65911_I2C_ADDR, + TPS65911_VDDCTRL_SR_DATA); + udelay(10 * 1000); +} From 8ed2bd1d1b908ff71925b80b6fe611c5384b407d Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:35 +0200 Subject: [PATCH 13/16] ARM: tegra: expose crypto module for all Tegra SoCs Move crypto module from T20 only into common Tegra dir. Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/mach-tegra/Kconfig | 5 +++++ arch/arm/mach-tegra/Makefile | 1 + arch/arm/mach-tegra/{tegra20 => }/crypto.c | 0 arch/arm/mach-tegra/{tegra20 => }/crypto.h | 0 arch/arm/mach-tegra/tegra20/Kconfig | 1 + arch/arm/mach-tegra/tegra20/Makefile | 2 +- 6 files changed, 8 insertions(+), 1 deletion(-) rename arch/arm/mach-tegra/{tegra20 => }/crypto.c (100%) rename arch/arm/mach-tegra/{tegra20 => }/crypto.h (100%) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 4fc79ebadb..5b0cd92d9e 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -15,6 +15,11 @@ config SPL_SERIAL config TEGRA_CLKRST bool +config TEGRA_CRYPTO + bool "Tegra AES128 crypto module" + select AES + default n + config TEGRA_GP_PADCTRL bool diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index 7165d70a60..9147050b32 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_TEGRA_GP_PADCTRL) += ap.o obj-y += board.o board2.o obj-y += cache.o obj-$(CONFIG_TEGRA_CLKRST) += clock.o +obj-$(CONFIG_$(SPL_)TEGRA_CRYPTO) += crypto.o obj-$(CONFIG_TEGRA_PINCTRL) += pinmux-common.o obj-$(CONFIG_TEGRA_PMC) += powergate.o obj-y += xusb-padctl-dummy.o diff --git a/arch/arm/mach-tegra/tegra20/crypto.c b/arch/arm/mach-tegra/crypto.c similarity index 100% rename from arch/arm/mach-tegra/tegra20/crypto.c rename to arch/arm/mach-tegra/crypto.c diff --git a/arch/arm/mach-tegra/tegra20/crypto.h b/arch/arm/mach-tegra/crypto.h similarity index 100% rename from arch/arm/mach-tegra/tegra20/crypto.h rename to arch/arm/mach-tegra/crypto.h diff --git a/arch/arm/mach-tegra/tegra20/Kconfig b/arch/arm/mach-tegra/tegra20/Kconfig index 955786c0c4..57d11024bf 100644 --- a/arch/arm/mach-tegra/tegra20/Kconfig +++ b/arch/arm/mach-tegra/tegra20/Kconfig @@ -3,6 +3,7 @@ if TEGRA20 config TEGRA_LP0 bool select TEGRA_CLOCK_SCALING + select TEGRA_CRYPTO config TEGRA_PMU bool diff --git a/arch/arm/mach-tegra/tegra20/Makefile b/arch/arm/mach-tegra/tegra20/Makefile index bb17c90cca..67454ff5f4 100644 --- a/arch/arm/mach-tegra/tegra20/Makefile +++ b/arch/arm/mach-tegra/tegra20/Makefile @@ -13,6 +13,6 @@ CFLAGS_warmboot_avp.o = -march=armv4t -U__LINUX_ARM_ARCH__ \ CFLAGS_REMOVE_warmboot_avp.o := $(LTO_CFLAGS) obj-y += clock.o funcmux.o pinmux.o -obj-$(CONFIG_TEGRA_LP0) += warmboot.o crypto.o warmboot_avp.o +obj-$(CONFIG_TEGRA_LP0) += warmboot.o warmboot_avp.o obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o obj-$(CONFIG_TEGRA_PMU) += pmu.o From bab087802a8c2237f9d9c4aec95918fea52e73d5 Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:36 +0200 Subject: [PATCH 14/16] ARM: tegra: crypto: extend crypto functional Add support for encryption, decryption and signinig with non-zero key saving backward compatibility. Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/include/asm/arch-tegra/crypto.h | 47 ++++++++++++++++++ arch/arm/mach-tegra/crypto.c | 63 +++++++++++++++++------- arch/arm/mach-tegra/crypto.h | 19 ------- 3 files changed, 91 insertions(+), 38 deletions(-) create mode 100644 arch/arm/include/asm/arch-tegra/crypto.h delete mode 100644 arch/arm/mach-tegra/crypto.h diff --git a/arch/arm/include/asm/arch-tegra/crypto.h b/arch/arm/include/asm/arch-tegra/crypto.h new file mode 100644 index 0000000000..7646163b97 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra/crypto.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010 - 2011 NVIDIA Corporation + */ + +#ifndef _CRYPTO_H_ +#define _CRYPTO_H_ + +/** + * Sign a block of data + * + * \param source Source data + * \param length Size of source data + * \param signature Destination address for signature, AES_KEY_LENGTH bytes + */ +int sign_data_block(u8 *source, unsigned int length, u8 *signature); + +/** + * Sign an encrypted block of data + * + * \param source Source data + * \param length Size of source data + * \param signature Destination address for signature, AES_KEY_LENGTH bytes + * \param key AES128 encryption key + */ +int sign_enc_data_block(u8 *source, unsigned int length, u8 *signature, u8 *key); + +/** + * Encrypt a block of data + * + * \param source Source data + * \param length Size of source data + * \param key AES128 encryption key + */ +int encrypt_data_block(u8 *source, unsigned int length, u8 *key); + +/** + * Decrypt a block of data + * + * \param source Source data + * \param length Size of source data + * \param key AES128 encryption key + */ +int decrypt_data_block(u8 *source, unsigned int length, u8 *key); + +#endif /* #ifndef _CRYPTO_H_ */ diff --git a/arch/arm/mach-tegra/crypto.c b/arch/arm/mach-tegra/crypto.c index 1efaa5c3ec..893da35e0b 100644 --- a/arch/arm/mach-tegra/crypto.c +++ b/arch/arm/mach-tegra/crypto.c @@ -7,7 +7,7 @@ #include #include #include -#include "crypto.h" +#include #include "uboot_aes.h" static u8 zero_key[16]; @@ -17,6 +17,7 @@ static u8 zero_key[16]; enum security_op { SECURITY_SIGN = 1 << 0, /* Sign the data */ SECURITY_ENCRYPT = 1 << 1, /* Encrypt the data */ + SECURITY_DECRYPT = 1 << 2, /* Dectypt the data */ }; /** @@ -54,7 +55,7 @@ static void sign_object(u8 *key, u8 *key_schedule, u8 *src, u8 *dst, u8 left[AES128_KEY_LENGTH]; u8 k1[AES128_KEY_LENGTH]; u8 *cbc_chain_data; - unsigned i; + unsigned int i; cbc_chain_data = zero_key; /* Convenient array of 0's for IV */ @@ -92,7 +93,7 @@ static void sign_object(u8 *key, u8 *key_schedule, u8 *src, u8 *dst, } /** - * Encrypt and sign a block of data (depending on security mode). + * Decrypt, encrypt or sign a block of data (depending on security mode). * * \param key Input AES key, length AES128_KEY_LENGTH * \param oper Security operations mask to perform (enum security_op) @@ -100,44 +101,68 @@ static void sign_object(u8 *key, u8 *key_schedule, u8 *src, u8 *dst, * \param length Size of source data * \param sig_dst Destination address for signature, AES128_KEY_LENGTH bytes */ -static int encrypt_and_sign(u8 *key, enum security_op oper, u8 *src, - u32 length, u8 *sig_dst) +static int tegra_crypto_core(u8 *key, enum security_op oper, u8 *src, + u32 length, u8 *sig_dst) { u32 num_aes_blocks; u8 key_schedule[AES128_EXPAND_KEY_LENGTH]; u8 iv[AES128_KEY_LENGTH] = {0}; - debug("encrypt_and_sign: length = %d\n", length); + debug("%s: length = %d\n", __func__, length); - /* - * The only need for a key is for signing/checksum purposes, so - * if not encrypting, expand a key of 0s. - */ - aes_expand_key(oper & SECURITY_ENCRYPT ? key : zero_key, - AES128_KEY_LENGTH, key_schedule); + aes_expand_key(key, AES128_KEY_LENGTH, key_schedule); num_aes_blocks = (length + AES128_KEY_LENGTH - 1) / AES128_KEY_LENGTH; + if (oper & SECURITY_DECRYPT) { + /* Perform this in place, resulting in src being decrypted. */ + debug("%s: begin decryption\n", __func__); + aes_cbc_decrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv, src, + src, num_aes_blocks); + debug("%s: end decryption\n", __func__); + } + if (oper & SECURITY_ENCRYPT) { /* Perform this in place, resulting in src being encrypted. */ - debug("encrypt_and_sign: begin encryption\n"); + debug("%s: begin encryption\n", __func__); aes_cbc_encrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv, src, src, num_aes_blocks); - debug("encrypt_and_sign: end encryption\n"); + debug("%s: end encryption\n", __func__); } if (oper & SECURITY_SIGN) { /* encrypt the data, overwriting the result in signature. */ - debug("encrypt_and_sign: begin signing\n"); + debug("%s: begin signing\n", __func__); sign_object(key, key_schedule, src, sig_dst, num_aes_blocks); - debug("encrypt_and_sign: end signing\n"); + debug("%s: end signing\n", __func__); } return 0; } -int sign_data_block(u8 *source, unsigned length, u8 *signature) +/** + * Tegra crypto group + */ +int sign_data_block(u8 *source, unsigned int length, u8 *signature) { - return encrypt_and_sign(zero_key, SECURITY_SIGN, source, - length, signature); + return tegra_crypto_core(zero_key, SECURITY_SIGN, source, + length, signature); +} + +int sign_enc_data_block(u8 *source, unsigned int length, u8 *signature, u8 *key) +{ + return tegra_crypto_core(key, SECURITY_SIGN, source, + length, signature); +} + +int encrypt_data_block(u8 *source, unsigned int length, u8 *key) +{ + return tegra_crypto_core(key, SECURITY_ENCRYPT, source, + length, NULL); +} + +int decrypt_data_block(u8 *source, unsigned int length, u8 *key) +{ + return tegra_crypto_core(key, SECURITY_DECRYPT, source, + length, NULL); } diff --git a/arch/arm/mach-tegra/crypto.h b/arch/arm/mach-tegra/crypto.h deleted file mode 100644 index a773d03fc7..0000000000 --- a/arch/arm/mach-tegra/crypto.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2011 The Chromium OS Authors. - * (C) Copyright 2010 - 2011 NVIDIA Corporation - */ - -#ifndef _CRYPTO_H_ -#define _CRYPTO_H_ - -/** - * Sign a block of data - * - * \param source Source data - * \param length Size of source data - * \param signature Destination address for signature, AES_KEY_LENGTH bytes - */ -int sign_data_block(u8 *source, unsigned length, u8 *signature); - -#endif /* #ifndef _CRYPTO_H_ */ From 327ff8e0a49e2e16ac946d059cae7df964c6ea59 Mon Sep 17 00:00:00 2001 From: Ramin Khonsari Date: Tue, 14 Feb 2023 19:35:37 +0200 Subject: [PATCH 15/16] ARM: tegra30: implement BCT patching This function allows updating bootloader from u-boot on production devices without need in host PC. Be aware! It works only with re-crypted BCT. Tested-by: Andreas Westman Dorcsak # ASUS TF T30 Tested-by: Svyatoslav Ryhel # LG P895 T30 Signed-off-by: Ramin Khonsari Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/mach-tegra/Kconfig | 9 ++++ arch/arm/mach-tegra/tegra30/Makefile | 1 + arch/arm/mach-tegra/tegra30/bct.c | 79 ++++++++++++++++++++++++++++ arch/arm/mach-tegra/tegra30/bct.h | 42 +++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 arch/arm/mach-tegra/tegra30/bct.c create mode 100644 arch/arm/mach-tegra/tegra30/bct.h diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 5b0cd92d9e..8490d42a7b 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -229,4 +229,13 @@ config CMD_ENTERRCM for mechanical button actuators, or hooking up relays/... to the button. +config CMD_EBTUPDATE + bool "Enable 'ebtupdate' command" + depends on TEGRA30 + select TEGRA_CRYPTO + help + Updating u-boot from within u-boot in rather complex or even + impossible on production devices. To make it easier procedure of + re-cryption was created. If your device was re-crypted choose Y. + endif diff --git a/arch/arm/mach-tegra/tegra30/Makefile b/arch/arm/mach-tegra/tegra30/Makefile index 9f170576e7..28dd486d8d 100644 --- a/arch/arm/mach-tegra/tegra30/Makefile +++ b/arch/arm/mach-tegra/tegra30/Makefile @@ -3,5 +3,6 @@ # Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved. obj-$(CONFIG_SPL_BUILD) += cpu.o +obj-$(CONFIG_$(SPL_)CMD_EBTUPDATE) += bct.o obj-y += clock.o funcmux.o pinmux.o diff --git a/arch/arm/mach-tegra/tegra30/bct.c b/arch/arm/mach-tegra/tegra30/bct.c new file mode 100644 index 0000000000..c56958da69 --- /dev/null +++ b/arch/arm/mach-tegra/tegra30/bct.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022, Ramin + * Copyright (c) 2022, Svyatoslav Ryhel + */ + +#include +#include +#include +#include +#include "bct.h" +#include "uboot_aes.h" + +/* + * @param bct boot config table start in RAM + * @param ect bootloader start in RAM + * @param ebt_size bootloader file size in bytes + * Return: 0, or 1 if failed + */ +static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size) +{ + struct nvboot_config_table *bct_tbl = NULL; + u8 ebt_hash[AES128_KEY_LENGTH] = { 0 }; + u8 sbk[AES128_KEY_LENGTH] = { 0 }; + u8 *bct_hash = bct; + int ret; + + bct += BCT_HASH; + + memcpy(sbk, (u8 *)(bct + BCT_LENGTH), + NVBOOT_CMAC_AES_HASH_LENGTH * 4); + + ret = decrypt_data_block(bct, BCT_LENGTH, sbk); + if (ret) + return 1; + + ebt_size = roundup(ebt_size, EBT_ALIGNMENT); + + ret = encrypt_data_block(ebt, ebt_size, sbk); + if (ret) + return 1; + + ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk); + if (ret) + return 1; + + bct_tbl = (struct nvboot_config_table *)bct; + + memcpy((u8 *)&bct_tbl->bootloader[0].crypto_hash, + ebt_hash, NVBOOT_CMAC_AES_HASH_LENGTH * 4); + bct_tbl->bootloader[0].entry_point = CONFIG_SPL_TEXT_BASE; + bct_tbl->bootloader[0].load_addr = CONFIG_SPL_TEXT_BASE; + bct_tbl->bootloader[0].length = ebt_size; + + ret = encrypt_data_block(bct, BCT_LENGTH, sbk); + if (ret) + return 1; + + ret = sign_enc_data_block(bct, BCT_LENGTH, bct_hash, sbk); + if (ret) + return 1; + + return 0; +} + +static int do_ebtupdate(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + u32 bct_addr = hextoul(argv[1], NULL); + u32 ebt_addr = hextoul(argv[2], NULL); + u32 ebt_size = hextoul(argv[3], NULL); + + return bct_patch((u8 *)bct_addr, (u8 *)ebt_addr, ebt_size); +} + +U_BOOT_CMD(ebtupdate, 4, 0, do_ebtupdate, + "update bootloader on re-crypted Tegra30 devices", + "" +); diff --git a/arch/arm/mach-tegra/tegra30/bct.h b/arch/arm/mach-tegra/tegra30/bct.h new file mode 100644 index 0000000000..9797384da3 --- /dev/null +++ b/arch/arm/mach-tegra/tegra30/bct.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _BCT_H_ +#define _BCT_H_ + +/* + * Defines the BCT parametres for T30 + */ +#define BCT_LENGTH 0x17E0 +#define BCT_HASH 0x10 +#define EBT_ALIGNMENT 0x10 + +/* + * Defines the CMAC-AES-128 hash length in 32 bit words. (128 bits = 4 words) + */ +#define NVBOOT_CMAC_AES_HASH_LENGTH 4 + +/* + * Defines the maximum number of bootloader descriptions in the BCT. + */ +#define NVBOOT_MAX_BOOTLOADERS 4 + +struct nv_bootloader_info { + u32 version; + u32 start_blk; + u32 start_page; + u32 length; + u32 load_addr; + u32 entry_point; + u32 attribute; + u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH]; +}; + +struct nvboot_config_table { + u32 unused0[4]; + u32 boot_data_version; + u32 unused1[972]; + struct nv_bootloader_info bootloader[NVBOOT_MAX_BOOTLOADERS]; + u32 unused2[508]; +}; + +#endif /* _BCT_H_ */ From 5a8fe1ee818e0f8a74fa088f6a3d705a01b6afbe Mon Sep 17 00:00:00 2001 From: Svyatoslav Ryhel Date: Tue, 14 Feb 2023 19:35:38 +0200 Subject: [PATCH 16/16] ARM: tegra20: implement BCT patching This function allows updating bootloader from u-boot on production devices without need in host PC. Be aware! It works only with re-crypt BCT. Tested-by: Robert Eckelmann # ASUS TF101 T20 Signed-off-by: Ramin Khonsari Signed-off-by: Svyatoslav Ryhel Signed-off-by: Tom --- arch/arm/mach-tegra/Kconfig | 2 +- arch/arm/mach-tegra/tegra20/Makefile | 5 +- arch/arm/mach-tegra/tegra20/bct.c | 79 ++++++++++++++++++++++++++++ arch/arm/mach-tegra/tegra20/bct.h | 42 +++++++++++++++ doc/usage/cmd/ebtupdate.rst | 69 ++++++++++++++++++++++++ 5 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 arch/arm/mach-tegra/tegra20/bct.c create mode 100644 arch/arm/mach-tegra/tegra20/bct.h create mode 100644 doc/usage/cmd/ebtupdate.rst diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 8490d42a7b..464bd0798f 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -231,7 +231,7 @@ config CMD_ENTERRCM config CMD_EBTUPDATE bool "Enable 'ebtupdate' command" - depends on TEGRA30 + depends on TEGRA20 || TEGRA30 select TEGRA_CRYPTO help Updating u-boot from within u-boot in rather complex or even diff --git a/arch/arm/mach-tegra/tegra20/Makefile b/arch/arm/mach-tegra/tegra20/Makefile index 67454ff5f4..991cabeec5 100644 --- a/arch/arm/mach-tegra/tegra20/Makefile +++ b/arch/arm/mach-tegra/tegra20/Makefile @@ -2,9 +2,8 @@ # # (C) Copyright 2010,2011 Nvidia Corporation. -ifdef CONFIG_SPL_BUILD -obj-y += cpu.o -endif +obj-$(CONFIG_SPL_BUILD) += cpu.o +obj-$(CONFIG_$(SPL_)CMD_EBTUPDATE) += bct.o # The AVP is ARMv4T architecture so we must use special compiler # flags for any startup files it might use. diff --git a/arch/arm/mach-tegra/tegra20/bct.c b/arch/arm/mach-tegra/tegra20/bct.c new file mode 100644 index 0000000000..5eb48990b6 --- /dev/null +++ b/arch/arm/mach-tegra/tegra20/bct.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022, Ramin + * Copyright (c) 2022, Svyatoslav Ryhel + */ + +#include +#include +#include +#include +#include "bct.h" +#include "uboot_aes.h" + +/* + * @param bct boot config table start in RAM + * @param ect bootloader start in RAM + * @param ebt_size bootloader file size in bytes + * Return: 0, or 1 if failed + */ +static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size) +{ + struct nvboot_config_table *bct_tbl = NULL; + u8 ebt_hash[AES128_KEY_LENGTH] = { 0 }; + u8 sbk[AES128_KEY_LENGTH] = { 0 }; + u8 *bct_hash = bct; + int ret; + + bct += BCT_HASH; + + memcpy(sbk, (u8 *)(bct + BCT_LENGTH), + NVBOOT_CMAC_AES_HASH_LENGTH * 4); + + ret = decrypt_data_block(bct, BCT_LENGTH, sbk); + if (ret) + return 1; + + ebt_size = roundup(ebt_size, EBT_ALIGNMENT); + + ret = encrypt_data_block(ebt, ebt_size, sbk); + if (ret) + return 1; + + ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk); + if (ret) + return 1; + + bct_tbl = (struct nvboot_config_table *)bct; + + memcpy((u8 *)&bct_tbl->bootloader[0].crypto_hash, + ebt_hash, NVBOOT_CMAC_AES_HASH_LENGTH * 4); + bct_tbl->bootloader[0].entry_point = CONFIG_SPL_TEXT_BASE; + bct_tbl->bootloader[0].load_addr = CONFIG_SPL_TEXT_BASE; + bct_tbl->bootloader[0].length = ebt_size; + + ret = encrypt_data_block(bct, BCT_LENGTH, sbk); + if (ret) + return 1; + + ret = sign_enc_data_block(bct, BCT_LENGTH, bct_hash, sbk); + if (ret) + return 1; + + return 0; +} + +static int do_ebtupdate(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + u32 bct_addr = hextoul(argv[1], NULL); + u32 ebt_addr = hextoul(argv[2], NULL); + u32 ebt_size = hextoul(argv[3], NULL); + + return bct_patch((u8 *)bct_addr, (u8 *)ebt_addr, ebt_size); +} + +U_BOOT_CMD(ebtupdate, 4, 0, do_ebtupdate, + "update bootloader on re-crypted Tegra20 devices", + "" +); diff --git a/arch/arm/mach-tegra/tegra20/bct.h b/arch/arm/mach-tegra/tegra20/bct.h new file mode 100644 index 0000000000..4b78aef7cf --- /dev/null +++ b/arch/arm/mach-tegra/tegra20/bct.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _BCT_H_ +#define _BCT_H_ + +/* + * Defines the BCT parametres for T20 + */ +#define BCT_LENGTH 0xFE0 +#define BCT_HASH 0x10 +#define EBT_ALIGNMENT 0x10 + +/* + * Defines the CMAC-AES-128 hash length in 32 bit words. (128 bits = 4 words) + */ +#define NVBOOT_CMAC_AES_HASH_LENGTH 4 + +/* + * Defines the maximum number of bootloader descriptions in the BCT. + */ +#define NVBOOT_MAX_BOOTLOADERS 4 + +struct nv_bootloader_info { + u32 version; + u32 start_blk; + u32 start_page; + u32 length; + u32 load_addr; + u32 entry_point; + u32 attribute; + u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH]; +}; + +struct nvboot_config_table { + u32 unused0[4]; + u32 boot_data_version; + u32 unused1[668]; + struct nv_bootloader_info bootloader[NVBOOT_MAX_BOOTLOADERS]; + u32 unused2[508]; +}; + +#endif /* _BCT_H_ */ diff --git a/doc/usage/cmd/ebtupdate.rst b/doc/usage/cmd/ebtupdate.rst new file mode 100644 index 0000000000..040cef37ec --- /dev/null +++ b/doc/usage/cmd/ebtupdate.rst @@ -0,0 +1,69 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +ebtupdate command +============= + +Synopsis +-------- + +:: + + ebtupdate [ [] []] + +Description +----------- + +The "ebtupdate" command is used to self-update bootloader on Tegra 2 and Tegra 3 +production devices which were processed using re-cryption. + +The "ebtupdate" performs encryption of new bootloader and decryption, patching +and re-encryption of BCT "in situ". After BCT and bootloader can be written in +their respective places. + +bct + address of BCT block pre-loaded into RAM. + +ebt + address of the bootloader pre-loaded into RAM. + +size + size of the pre-loaded bootloader. + +Example +------- + +This is the boot log of a LG Optimus Vu: + +:: + + => mmc dev 0 1 + switch to partitions #1, OK + mmc0(part 1) is current device + => mmc read $kernel_addr_r 0 $boot_block_size + MMC read: dev # 0, block # 0, count 4096 ... 4096 blocks read: OK + => load mmc 0:1 $ramdisk_addr_r $bootloader_file + 684783 bytes read in 44 ms (14.8 MiB/s) + => size mmc 0:1 $bootloader_file + => ebtupdate $kernel_addr_r $ramdisk_addr_r $filesize + => mmc dev 0 1 + switch to partitions #1, OK + mmc0(part 1) is current device + => mmc write $kernel_addr_r 0 $boot_block_size + MMC write: dev # 0, block # 0, count 4096 ... 4096 blocks written: OK + => mmc dev 0 2 + switch to partitions #2, OK + mmc0(part 2) is current device + => mmc write $ramdisk_addr_r 0 $boot_block_size + MMC write: dev # 0, block # 0, count 4096 ... 4096 blocks written: OK + +Configuration +------------- + +The ebtupdate command is only available if CONFIG_CMD_EBTUPDATE=y and +only on Tegra 2 and Tegra 3 configurations. + +Return value +------------ + +The return value $? is set to 0 (true) if everything went successfully. If an +error occurs, the return value $? is set to 1 (false).