diff options
39 files changed, 2459 insertions, 192 deletions
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 85a03b512b6..73231824526 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -121,6 +121,7 @@ dtb-$(CONFIG_ARCH_TEGRA) += \ tegra124-nyan-big.dtb \ tegra124-cei-tk1-som.dtb \ tegra124-venice2.dtb \ + tegra124-xiaomi-mocha.dtb \ tegra186-p2771-0000-000.dtb \ tegra186-p2771-0000-500.dtb \ tegra210-p2371-0000.dtb \ diff --git a/arch/arm/dts/tegra124-xiaomi-mocha.dts b/arch/arm/dts/tegra124-xiaomi-mocha.dts new file mode 100644 index 00000000000..6cb1781566f --- /dev/null +++ b/arch/arm/dts/tegra124-xiaomi-mocha.dts @@ -0,0 +1,592 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; + +#include <dt-bindings/input/input.h> +#include "tegra124.dtsi" + +/ { + model = "Xiaomi Mi Pad A0101"; + compatible = "xiaomi,mocha", "nvidia,tegra124"; + + chosen { + stdout-path = &uartd; + }; + + aliases { + i2c0 = &pwr_i2c; + i2c1 = &gen1_i2c; + + mmc0 = &sdmmc4; /* eMMC */ + mmc1 = &sdmmc3; /* uSD slot */ + + usb0 = &usb1; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x80000000>; + }; + + host1x@50000000 { + dsia: dsi@54300000 { + status = "okay"; + + avdd-dsi-csi-supply = <&avdd_dsi_csi>; + nvidia,ganged-mode = <&dsib>; + + panel@0 { + compatible = "sharp,lq079l1sx01"; + reg = <0>; + + link2 = <&panel_secondary>; + + avdd-supply = <&avdd_lcd>; + vddio-supply = <&vdd_lcd_io>; + + vsp-supply = <&vsp_5v5_lcd>; + vsn-supply = <&vsn_5v5_lcd>; + + reset-gpios = <&gpio TEGRA_GPIO(H, 3) GPIO_ACTIVE_LOW>; + + backlight = <&lp8556>; + }; + }; + + dsib: dsi@54400000 { + status = "okay"; + + avdd-dsi-csi-supply = <&avdd_dsi_csi>; + + panel_secondary: panel@0 { + compatible = "sharp,lq079l1sx01"; + reg = <0>; + }; + }; + }; + + pinmux@70000868 { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + /* Keys pinmux */ + keys { + nvidia,pins = "kb_col0_pq0", + "kb_col6_pq6", + "kb_col7_pq7"; + nvidia,function = "rsvd2"; + nvidia,pull = <TEGRA_PIN_PULL_UP>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + hall-front { + nvidia,pins = "pi5"; + nvidia,function = "gmi"; + nvidia,pull = <TEGRA_PIN_PULL_UP>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + hall-back { + nvidia,pins = "gpio_w3_aud_pw3"; + nvidia,function = "spi1"; + nvidia,pull = <TEGRA_PIN_PULL_UP>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + + /* Leds pinmux */ + bl-en { + nvidia,pins = "pbb4"; + nvidia,function = "vgp4"; + nvidia,pull = <TEGRA_PIN_PULL_DOWN>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_DISABLE>; + }; + keys-led { + nvidia,pins = "ph1"; + nvidia,function = "pwm1"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_DISABLE>; + }; + + /* Panel pinmux */ + lcd-rst { + nvidia,pins = "ph3"; + nvidia,function = "gmi"; + nvidia,pull = <TEGRA_PIN_PULL_UP>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_DISABLE>; + }; + lcd-vsp { + nvidia,pins = "pi4"; + nvidia,function = "gmi"; + nvidia,pull = <TEGRA_PIN_PULL_DOWN>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_DISABLE>; + }; + lcd-vsn { + nvidia,pins = "kb_row10_ps2"; + nvidia,function = "kbc"; + nvidia,pull = <TEGRA_PIN_PULL_DOWN>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_DISABLE>; + }; + lcd-id { + nvidia,pins = "kb_row6_pr6"; + nvidia,function = "displaya_alt"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + lcd-pwm { + nvidia,pins = "ph2"; + nvidia,function = "pwm2"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_DISABLE>; + }; + + /* SDMMC3 pinmux */ + sdmmc3-clk { + nvidia,pins = "sdmmc3_clk_pa6"; + nvidia,function = "sdmmc3"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + sdmmc3-cmd { + nvidia,pins = "sdmmc3_cmd_pa7", + "sdmmc3_dat0_pb7", + "sdmmc3_dat1_pb6", + "sdmmc3_dat2_pb5", + "sdmmc3_dat3_pb4", + "sdmmc3_clk_lb_out_pee4", + "sdmmc3_clk_lb_in_pee5"; + nvidia,function = "sdmmc3"; + nvidia,pull = <TEGRA_PIN_PULL_UP>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + sdmmc3-cd { + nvidia,pins = "sdmmc3_cd_n_pv2"; + nvidia,function = "sdmmc3"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + usd-pwr { + nvidia,pins = "kb_row0_pr0"; + nvidia,function = "rsvd4"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_DISABLE>; + }; + + /* SDMMC4 pinmux */ + sdmmc4-clk { + nvidia,pins = "sdmmc4_clk_pcc4"; + nvidia,function = "sdmmc4"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + sdmmc4-cmd { + nvidia,pins = "sdmmc4_cmd_pt7", + "sdmmc4_dat0_paa0", + "sdmmc4_dat1_paa1", + "sdmmc4_dat2_paa2", + "sdmmc4_dat3_paa3", + "sdmmc4_dat4_paa4", + "sdmmc4_dat5_paa5", + "sdmmc4_dat6_paa6", + "sdmmc4_dat7_paa7"; + nvidia,function = "sdmmc4"; + nvidia,pull = <TEGRA_PIN_PULL_UP>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + + /* I2C pinmux */ + gen1-i2c { + nvidia,pins = "gen1_i2c_sda_pc5", + "gen1_i2c_scl_pc4"; + nvidia,function = "i2c1"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + nvidia,lock = <1>; + nvidia,open-drain = <1>; + }; + gen2-i2c { + nvidia,pins = "gen2_i2c_scl_pt5", + "gen2_i2c_sda_pt6"; + nvidia,function = "i2c2"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + nvidia,lock = <1>; + nvidia,open-drain = <1>; + }; + cam-i2c { + nvidia,pins = "cam_i2c_scl_pbb1", + "cam_i2c_sda_pbb2"; + nvidia,function = "i2c3"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + nvidia,lock = <1>; + nvidia,open-drain = <1>; + }; + ddc-i2c { + nvidia,pins = "ddc_scl_pv4", + "ddc_sda_pv5"; + nvidia,function = "i2c4"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + }; + pwr-i2c { + nvidia,pins = "pwr_i2c_scl_pz6", + "pwr_i2c_sda_pz7"; + nvidia,function = "i2cpwr"; + nvidia,pull = <TEGRA_PIN_PULL_NONE>; + nvidia,tristate = <TEGRA_PIN_DISABLE>; + nvidia,enable-input = <TEGRA_PIN_ENABLE>; + nvidia,open-drain = <1>; + }; + + dsi-b { + nvidia,pins = "mipi_pad_ctrl_dsi_b"; + nvidia,function = "dsi_b"; + }; + + /* GPIO power/drive control */ + drive-sdio1 { + nvidia,pins = "drive_sdio1"; + nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; + nvidia,schmitt = <TEGRA_PIN_DISABLE>; + nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>; + nvidia,pull-down-strength = <32>; + nvidia,pull-up-strength = <42>; + nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>; + nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>; + }; + + drive-sdio3 { + nvidia,pins = "drive_sdio3"; + nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; + nvidia,schmitt = <TEGRA_PIN_DISABLE>; + nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>; + nvidia,pull-down-strength = <20>; + nvidia,pull-up-strength = <36>; + nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>; + nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>; + }; + + drive-gma { + nvidia,pins = "drive_gma"; + nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; + nvidia,schmitt = <TEGRA_PIN_DISABLE>; + nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>; + nvidia,pull-down-strength = <1>; + nvidia,pull-up-strength = <2>; + nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>; + nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>; + }; + }; + }; + + uartd: serial@70006300 { + status = "okay"; + }; + + gen1_i2c: i2c@7000c000 { + status = "okay"; + clock-frequency = <400000>; + + lp8556: backlight@2c { + compatible = "ti,lp8556"; + reg = <0x2c>; + + dev-ctrl = /bits/ 8 <0x83>; + init-brt = /bits/ 8 <0x1f>; + + power-supply = <&vdd_3v3_sys>; + enable-supply = <&vddio_1v8_bl>; + + rom-98h { + rom-addr = /bits/ 8 <0x98>; + rom-val = /bits/ 8 <0x80>; + }; + + rom-9eh { + rom-addr = /bits/ 8 <0x9e>; + rom-val = /bits/ 8 <0x21>; + }; + + rom-a0h { + rom-addr = /bits/ 8 <0xa0>; + rom-val = /bits/ 8 <0xff>; + }; + + rom-a1h { + rom-addr = /bits/ 8 <0xa1>; + rom-val = /bits/ 8 <0x3f>; + }; + + rom-a2h { + rom-addr = /bits/ 8 <0xa2>; + rom-val = /bits/ 8 <0x20>; + }; + + rom-a3h { + rom-addr = /bits/ 8 <0xa3>; + rom-val = /bits/ 8 <0x00>; + }; + + rom-a4h { + rom-addr = /bits/ 8 <0xa4>; + rom-val = /bits/ 8 <0x72>; + }; + + rom-a5h { + rom-addr = /bits/ 8 <0xa5>; + rom-val = /bits/ 8 <0x24>; + }; + + rom-a6h { + rom-addr = /bits/ 8 <0xa6>; + rom-val = /bits/ 8 <0x80>; + }; + + rom-a7h { + rom-addr = /bits/ 8 <0xa7>; + rom-val = /bits/ 8 <0xf5>; + }; + + rom-a8h { + rom-addr = /bits/ 8 <0xa8>; + rom-val = /bits/ 8 <0x24>; + }; + + rom-a9h { + rom-addr = /bits/ 8 <0xa9>; + rom-val = /bits/ 8 <0xb2>; + }; + + rom-aah { + rom-addr = /bits/ 8 <0xaa>; + rom-val = /bits/ 8 <0x8f>; + }; + + rom-aeh { + rom-addr = /bits/ 8 <0xae>; + rom-val = /bits/ 8 <0x0f>; + }; + }; + }; + + pwr_i2c: i2c@7000d000 { + status = "okay"; + clock-frequency = <400000>; + + /* Texas Instruments TPS65913 PMIC */ + pmic: tps65913@58 { + compatible = "ti,tps65913"; + reg = <0x58>; + + interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>; + #interrupt-cells = <2>; + interrupt-controller; + + ti,system-power-controller; + + palmas_gpio: gpio { + compatible = "ti,palmas-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + pinmux { + compatible = "ti,tps65913-pinctrl"; + + pinctrl-names = "default"; + pinctrl-0 = <&palmas_default>; + + palmas_default: pinmux { + pin_gpio4 { + pins = "gpio4"; + function = "gpio"; + }; + }; + }; + + pmic { + compatible = "ti,tps65913-pmic"; + + regulators { + vdd_1v8_vio: smps8 { + regulator-name = "vdd_1v8_gen"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_hv_sdmmc: smps9 { + regulator-name = "vdd_hv_sdmmc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + avdd_lcd: ldo2 { + regulator-name = "avdd_lcd"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + + avdd_dsi_csi: ldo5 { + regulator-name = "avdd_dsi_csi"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + }; + + vddio_usd: ldo9 { + regulator-name = "vddio_sdmmc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + avdd_usb: ldousb { + regulator-name = "vdd_usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + }; + }; + }; + }; + + sdmmc3: sdhci@700b0400 { + status = "okay"; + bus-width = <4>; + + cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>; + power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>; + + vmmc-supply = <&vdd_hv_sdmmc>; + vqmmc-supply = <&vddio_usd>; + }; + + sdmmc4: sdhci@700b0600 { + status = "okay"; + bus-width = <8>; + non-removable; + + vmmc-supply = <&vdd_hv_sdmmc>; + vqmmc-supply = <&vdd_1v8_vio>; + }; + + usb1: usb@7d000000 { + status = "okay"; + dr_mode = "otg"; + }; + + clk32k_in: clock-32k { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "ref-oscillator"; + }; + + extcon-keys { + compatible = "gpio-keys"; + + switch-back-hall-sensor { + label = "Hall sensor (back)"; + gpios = <&gpio TEGRA_GPIO(W, 3) GPIO_ACTIVE_LOW>; + linux,code = <SW_LID>; + }; + + switch-front-hall-sensor { + label = "Hall sensor (front)"; + gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>; + linux,code = <SW_LID>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + key-power { + label = "Power"; + gpios = <&gpio TEGRA_GPIO(Q, 0) GPIO_ACTIVE_LOW>; + linux,code = <KEY_ENTER>; + }; + + key-volume-down { + label = "Volume Down"; + gpios = <&gpio TEGRA_GPIO(Q, 7) GPIO_ACTIVE_LOW>; + linux,code = <KEY_DOWN>; + }; + + key-volume-up { + label = "Volume Up"; + gpios = <&gpio TEGRA_GPIO(Q, 6) GPIO_ACTIVE_LOW>; + linux,code = <KEY_UP>; + }; + }; + + vdd_3v3_sys: regulator-bl-en { + compatible = "regulator-fixed"; + regulator-name = "vdd_5v0_bl"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + enable-active-high; + }; + + vddio_1v8_bl: regulator-bl-io { + compatible = "regulator-fixed"; + regulator-name = "vddio_1v8_bl"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + enable-active-high; + gpio = <&gpio TEGRA_GPIO(BB, 4) GPIO_ACTIVE_HIGH>; + }; + + vdd_lcd_io: regulator-lcdvio { + compatible = "regulator-fixed"; + regulator-name = "dvdd_lcd"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + enable-active-high; + gpio = <&palmas_gpio 4 GPIO_ACTIVE_HIGH>; + }; + + vsp_5v5_lcd: regulator-vsp { + compatible = "regulator-fixed"; + regulator-name = "avdd_lcd_vsp"; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + enable-active-high; + gpio = <&gpio TEGRA_GPIO(I, 4) GPIO_ACTIVE_HIGH>; + }; + + vsn_5v5_lcd: regulator-vsn { + compatible = "regulator-fixed"; + regulator-name = "avdd_lcd_vsn"; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + enable-active-high; + gpio = <&gpio TEGRA_GPIO(S, 2) GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm/dts/tegra20-u-boot.dtsi b/arch/arm/dts/tegra20-u-boot.dtsi index fa582bcb9fd..b74aa5bb0d4 100644 --- a/arch/arm/dts/tegra20-u-boot.dtsi +++ b/arch/arm/dts/tegra20-u-boot.dtsi @@ -9,5 +9,9 @@ dc@54200000 { bootph-all; }; + + dc@54240000 { + bootph-all; + }; }; }; diff --git a/arch/arm/dts/tegra30-htc-endeavoru.dts b/arch/arm/dts/tegra30-htc-endeavoru.dts index dbff795bd89..8a0ba3c07cc 100644 --- a/arch/arm/dts/tegra30-htc-endeavoru.dts +++ b/arch/arm/dts/tegra30-htc-endeavoru.dts @@ -48,7 +48,17 @@ avdd-dsi-csi-supply = <&avdd_dsi_csi>; - panel = <&panel>; + panel@0 { + compatible = "htc,edge-panel"; + reg = <0>; + + reset-gpios = <&gpio TEGRA_GPIO(N, 6) GPIO_ACTIVE_LOW>; + + vdd-supply = <&vdd_3v3_panel>; + vddio-supply = <&vdd_1v8_panel>; + + backlight = <&backlight>; + }; }; }; @@ -1292,17 +1302,6 @@ }; }; - panel: panel { - compatible = "htc,edge-panel"; - - reset-gpios = <&gpio TEGRA_GPIO(N, 6) GPIO_ACTIVE_LOW>; - - vdd-supply = <&vdd_3v3_panel>; - vddio-supply = <&vdd_1v8_panel>; - - backlight = <&backlight>; - }; - vcore_emmc: regulator-emmc { compatible = "regulator-fixed"; regulator-name = "vdd_2v85_sdmmc"; diff --git a/arch/arm/include/asm/arch-tegra124/pinmux.h b/arch/arm/include/asm/arch-tegra124/pinmux.h index 3aba17d21e4..fbe15fc612d 100644 --- a/arch/arm/include/asm/arch-tegra124/pinmux.h +++ b/arch/arm/include/asm/arch-tegra124/pinmux.h @@ -578,6 +578,10 @@ static const char * const tegra_pinctrl_to_drvgrp[] = { [PMUX_DRVGRP_AO4] = "ao4", }; +static const char * const tegra_pinctrl_to_mipipadgrp[] = { + [PMUX_MIPIPADCTRLGRP_DSI_B] = "mipi_pad_ctrl_dsi_b", +}; + static const char * const tegra_pinctrl_to_func[] = { [PMUX_FUNC_DEFAULT] = "default", [PMUX_FUNC_BLINK] = "blink", diff --git a/arch/arm/include/asm/arch-tegra20/clock-tables.h b/arch/arm/include/asm/arch-tegra20/clock-tables.h index 861b3d5d07c..82685353bd1 100644 --- a/arch/arm/include/asm/arch-tegra20/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra20/clock-tables.h @@ -32,6 +32,7 @@ enum clock_id { CLOCK_ID_COUNT, /* number of clocks */ CLOCK_ID_NONE = -1, + CLOCK_ID_DISPLAY2 = CLOCK_ID_NONE, /* for compatibility */ }; /* The clocks supported by the hardware */ @@ -159,6 +160,7 @@ enum periph_id { PERIPH_ID_COUNT, PERIPH_ID_NONE = -1, + PERIPH_ID_DSIB = CLOCK_ID_NONE, /* for compatibility */ }; enum pll_out_id { diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 78b89729f19..4690dcb3ea6 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -247,7 +247,7 @@ config CMD_ENTERRCM config CMD_EBTUPDATE bool "Enable 'ebtupdate' command" - depends on TEGRA20 || TEGRA30 + depends on TEGRA20 || TEGRA30 || TEGRA124 select TEGRA_CRYPTO help Updating u-boot from within u-boot in rather complex or even diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 157e6c4911a..a375693481e 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -358,6 +358,13 @@ unsigned long clock_get_periph_rate(enum periph_id periph_id, break; } + /* + * PLLD/PLLD2 raw clock rate is never used, instead plld_out0 is used + * that is PLLD/PLLD2 halved. + */ + if (parent == CLOCK_ID_DISPLAY || parent == CLOCK_ID_DISPLAY2) + parent_rate /= 2; + return get_rate_from_divider(parent_rate, div); } @@ -449,6 +456,7 @@ unsigned clock_adjust_periph_pll_div(enum periph_id periph_id, enum clock_id parent, unsigned rate, int *extra_div) { unsigned effective_rate; + unsigned int parent_rate; int mux_bits, divider_bits, source; int divider; int xdiv = 0; @@ -457,7 +465,17 @@ unsigned clock_adjust_periph_pll_div(enum periph_id periph_id, source = get_periph_clock_source(periph_id, parent, &mux_bits, ÷r_bits); - divider = find_best_divider(divider_bits, pll_rate[parent], + /* + * Clocks derived from PLLD/D2 are actually sourced from its halved + * output, plld_out0/plld2_out0. No peripheral clocks use the raw + * PLLD/D2 frequency. This halving must be accounted for in derived + * clock calculations. + */ + parent_rate = pll_rate[parent]; + if (parent == CLOCK_ID_DISPLAY || parent == CLOCK_ID_DISPLAY2) + parent_rate /= 2; + + divider = find_best_divider(divider_bits, parent_rate, rate, &xdiv); if (extra_div) *extra_div = xdiv; @@ -685,6 +703,16 @@ int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon) else writel(base_reg, &simple_pll->pll_base); + /* + * Changing clocks was never intended in the U-Boot for Tegra. + * If a clock is changed after clock_init() the parent rate is wrong. + * Usually there is no reason to change peripheral clocks, but Display + * PLLs which needs to generate a precise pixelclock might be adjusted. + * Especially in the case of HDMI display with changing and prior + * unknown resolution. + */ + pll_rate[clkid] = clock_get_rate(clkid); + return 0; } diff --git a/arch/arm/mach-tegra/tegra124/Kconfig b/arch/arm/mach-tegra/tegra124/Kconfig index 84c8f86bad0..a62b055f7e6 100644 --- a/arch/arm/mach-tegra/tegra124/Kconfig +++ b/arch/arm/mach-tegra/tegra124/Kconfig @@ -30,6 +30,10 @@ config TARGET_CEI_TK1_SOM the SoC are assigned to which functions, and the PCIEe configuration. +config TARGET_MOCHA + bool "Xiaomi Tegra124 Mi Pad board" + select BOARD_LATE_INIT + config TARGET_NYAN_BIG bool "Google/NVIDIA Nyan-big Chromebook" select BOARD_LATE_INIT @@ -54,5 +58,6 @@ source "board/nvidia/jetson-tk1/Kconfig" source "board/nvidia/nyan-big/Kconfig" source "board/nvidia/venice2/Kconfig" source "board/toradex/apalis-tk1/Kconfig" +source "board/xiaomi/mocha/Kconfig" endif diff --git a/arch/arm/mach-tegra/tegra124/Makefile b/arch/arm/mach-tegra/tegra124/Makefile index dee790015a3..7b93db89c0f 100644 --- a/arch/arm/mach-tegra/tegra124/Makefile +++ b/arch/arm/mach-tegra/tegra124/Makefile @@ -6,6 +6,7 @@ # obj-$(CONFIG_XPL_BUILD) += cpu.o +obj-$(CONFIG_$(XPL_)CMD_EBTUPDATE) += bct.o obj-y += clock.o obj-y += pmc.o diff --git a/arch/arm/mach-tegra/tegra124/bct.c b/arch/arm/mach-tegra/tegra124/bct.c new file mode 100644 index 00000000000..a71aa87fce1 --- /dev/null +++ b/arch/arm/mach-tegra/tegra124/bct.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022, Ramin <raminterex@yahoo.com> + * Copyright (c) 2022, Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#include <command.h> +#include <log.h> +#include <vsprintf.h> +#include <asm/arch-tegra/crypto.h> +#include "bct.h" +#include "uboot_aes.h" + +/* Device with "sbk burned: false" will expose zero key */ +const u8 nosbk[AES128_KEY_LENGTH] = { 0 }; + +/* + * @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 bct_hash[AES128_KEY_LENGTH] = { 0 }; + u8 sbk[AES128_KEY_LENGTH] = { 0 }; + u8 *sbct = bct + UBCT_LENGTH; + bool encrypted; + int ret; + + ebt_size = roundup(ebt_size, EBT_ALIGNMENT); + + memcpy(sbk, (u8 *)(bct + UBCT_LENGTH + SBCT_LENGTH), + NVBOOT_CMAC_AES_HASH_LENGTH * 4); + + encrypted = memcmp(&sbk, &nosbk, AES128_KEY_LENGTH); + + if (encrypted) { + ret = decrypt_data_block(sbct, SBCT_LENGTH, sbk); + if (ret) + return 1; + + 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; + + if (encrypted) { + ret = encrypt_data_block(sbct, SBCT_LENGTH, sbk); + if (ret) + return 1; + } + + ret = sign_enc_data_block(sbct, SBCT_LENGTH, bct_hash, sbk); + if (ret) + return 1; + + memcpy((u8 *)&bct_tbl->crypto_hash, bct_hash, + NVBOOT_CMAC_AES_HASH_LENGTH * 4); + + 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 Tegra124 devices", + "" +); diff --git a/arch/arm/mach-tegra/tegra124/bct.h b/arch/arm/mach-tegra/tegra124/bct.h new file mode 100644 index 00000000000..eb0f712d595 --- /dev/null +++ b/arch/arm/mach-tegra/tegra124/bct.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _BCT_H_ +#define _BCT_H_ + +/* + * Defines the BCT parametres for T124 + */ +#define UBCT_LENGTH 0x6b0 /* bytes */ +#define SBCT_LENGTH 0x1950 /* bytes */ + +#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 RSA modulus length in 32 bit words used for PKC secure boot. + */ +#define NVBOOT_SE_RSA_MODULUS_LENGTH 64 + +/* + * 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; + + /* Specifies the AES-CMAC MAC or RSASSA-PSS signature of the BL. */ + u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH]; + u32 bl_rsa_sig[NVBOOT_SE_RSA_MODULUS_LENGTH]; +}; + +struct nvboot_config_table { + u32 ubct_unused1[196]; + u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH]; + u32 ubct_unused2[228]; + + u32 sbct_unused1[1318]; + u32 bootloader_used; + struct nv_bootloader_info bootloader[NVBOOT_MAX_BOOTLOADERS]; + u32 sbct_unused2; +}; + +#endif /* _BCT_H_ */ diff --git a/board/xiaomi/mocha/Kconfig b/board/xiaomi/mocha/Kconfig new file mode 100644 index 00000000000..25c61d4169e --- /dev/null +++ b/board/xiaomi/mocha/Kconfig @@ -0,0 +1,12 @@ +if TARGET_MOCHA + +config SYS_BOARD + default "mocha" + +config SYS_VENDOR + default "xiaomi" + +config SYS_CONFIG_NAME + default "mocha" + +endif diff --git a/board/xiaomi/mocha/MAINTAINERS b/board/xiaomi/mocha/MAINTAINERS new file mode 100644 index 00000000000..c3871a15a35 --- /dev/null +++ b/board/xiaomi/mocha/MAINTAINERS @@ -0,0 +1,8 @@ +MOCHA BOARD +M: Svyatoslav Ryhel <clamor95@gmail.com> +S: Maintained +F: arch/arm/dts/tegra124-xiaomi-mocha.dts +F: board/xiaomi/mocha/ +F: configs/mocha_defconfig +F: doc/board/xiaomi/mocha.rst +F: include/configs/mocha.h diff --git a/board/xiaomi/mocha/Makefile b/board/xiaomi/mocha/Makefile new file mode 100644 index 00000000000..c42e42639b3 --- /dev/null +++ b/board/xiaomi/mocha/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2024, Svyatoslav Ryhel <clamor95@gmail.com> +# + +obj-$(CONFIG_XPL_BUILD) += mocha-spl.o + +obj-y += mocha.o + diff --git a/board/xiaomi/mocha/mocha-spl.c b/board/xiaomi/mocha/mocha-spl.c new file mode 100644 index 00000000000..5fb11df0a93 --- /dev/null +++ b/board/xiaomi/mocha/mocha-spl.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Mocha SPL stage configuration + * + * (C) Copyright 2024 + * Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/tegra_i2c.h> +#include <linux/delay.h> + +#define TPS65913_I2C_ADDR (0x58 << 1) + +#define TPS65913_SMPS12_CTRL 0x20 +#define TPS65913_SMPS12_VOLTAGE 0x23 +#define TPS65913_SMPS45_CTRL 0x28 +#define TPS65913_SMPS45_VOLTAGE 0x2B +#define TPS65913_SMPS7_CTRL 0x30 +#define TPS65913_SMPS7_VOLTAGE 0x33 + +#define TPS65913_SMPS12_CTRL_DATA (0x5100 | TPS65913_SMPS12_CTRL) +#define TPS65913_SMPS12_VOLTAGE_DATA (0x3800 | TPS65913_SMPS12_VOLTAGE) +#define TPS65913_SMPS45_CTRL_DATA (0x5100 | TPS65913_SMPS45_CTRL) +#define TPS65913_SMPS45_VOLTAGE_DATA (0x3800 | TPS65913_SMPS45_VOLTAGE) +#define TPS65913_SMPS7_CTRL_DATA (0x5100 | TPS65913_SMPS7_CTRL) +#define TPS65913_SMPS7_VOLTAGE_DATA (0x4700 | TPS65913_SMPS7_VOLTAGE) + +void pmic_enable_cpu_vdd(void) +{ + /* Set CORE VDD to 1.150V. */ + tegra_i2c_ll_write(TPS65913_I2C_ADDR, TPS65913_SMPS7_VOLTAGE_DATA); + udelay(1000); + tegra_i2c_ll_write(TPS65913_I2C_ADDR, TPS65913_SMPS7_CTRL_DATA); + + udelay(1000); + + /* Set CPU VDD to 1.0V. */ + tegra_i2c_ll_write(TPS65913_I2C_ADDR, TPS65913_SMPS12_VOLTAGE_DATA); + udelay(1000); + tegra_i2c_ll_write(TPS65913_I2C_ADDR, TPS65913_SMPS12_CTRL_DATA); + udelay(10 * 1000); + + /* Set GPU VDD to 1.0V. */ + tegra_i2c_ll_write(TPS65913_I2C_ADDR, TPS65913_SMPS45_VOLTAGE_DATA); + udelay(1000); + tegra_i2c_ll_write(TPS65913_I2C_ADDR, TPS65913_SMPS45_CTRL_DATA); + udelay(10 * 1000); +} diff --git a/board/xiaomi/mocha/mocha.c b/board/xiaomi/mocha/mocha.c new file mode 100644 index 00000000000..5026d541a5f --- /dev/null +++ b/board/xiaomi/mocha/mocha.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2024 + * Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#include <dm.h> +#include <fdt_support.h> +#include <i2c.h> +#include <log.h> + +#ifdef CONFIG_MMC_SDHCI_TEGRA + +#define TPS65913_I2C_ADDRESS 0x58 +#define TPS65913_PRIMARY_SECONDARY_PAD2 0xfb +#define GPIO_4 BIT(0) +#define TPS65913_PRIMARY_SECONDARY_PAD3 0xfe +#define DVFS2 BIT(1) +#define DVFS1 BIT(0) + +/* We are using this function only till palmas pinctrl driver is available */ +void pin_mux_mmc(void) +{ + struct udevice *dev; + int ret; + + ret = i2c_get_chip_for_busnum(0, TPS65913_I2C_ADDRESS, 1, &dev); + if (ret) { + log_debug("%s: cannot find PMIC I2C chip\n", __func__); + return; + } + + /* GPIO4 function has to be GPIO */ + dm_i2c_reg_clrset(dev, TPS65913_PRIMARY_SECONDARY_PAD2, + GPIO_4, 0); + + /* DVFS1 and DVFS2 are disabled */ + dm_i2c_reg_clrset(dev, TPS65913_PRIMARY_SECONDARY_PAD3, + DVFS2 | DVFS1, 0); +} +#endif diff --git a/board/xiaomi/mocha/mocha.env b/board/xiaomi/mocha/mocha.env new file mode 100644 index 00000000000..d93e24316f6 --- /dev/null +++ b/board/xiaomi/mocha/mocha.env @@ -0,0 +1,23 @@ +#include <env/nvidia/prod_upd.env> + +button_cmd_0_name=Volume Down +button_cmd_0=bootmenu +button_cmd_1_name=Hall sensor (back) +button_cmd_1=poweroff +button_cmd_1_name=Hall sensor (front) +button_cmd_1=poweroff + +partitions=name=emmc,start=0,size=-,uuid=${uuid_gpt_rootfs} + +boot_block_size_r=0x400000 +boot_block_size=0x2000 +boot_dev=1 + +bootmenu_0=mount internal storage=usb start && ums 0 mmc 0; bootmenu +bootmenu_1=mount external storage=usb start && ums 0 mmc 1; bootmenu +bootmenu_2=fastboot=echo Starting Fastboot protocol ...; fastboot usb 0; bootmenu +bootmenu_3=update bootloader=run flash_uboot +bootmenu_4=reboot RCM=enterrcm +bootmenu_5=reboot=reset +bootmenu_6=power off=poweroff +bootmenu_delay=-1 diff --git a/common/edid.c b/common/edid.c index 48a737690db..e2ac7100a88 100644 --- a/common/edid.c +++ b/common/edid.c @@ -16,6 +16,197 @@ #include <linux/ctype.h> #include <linux/string.h> +#define TIMING(c, ha, hfp, hbp, hsl, va, vfp, vbp, vsl, f) \ + .pixelclock = { (c), (c), (c) }, \ + .hactive = { (ha), (ha), (ha) }, \ + .hfront_porch = { (hfp), (hfp), (hfp) }, \ + .hback_porch = { (hbp), (hbp), (hbp) }, \ + .hsync_len = { (hsl), (hsl), (hsl) }, \ + .vactive = { (va), (va), (va) }, \ + .vfront_porch = { (vfp), (vfp), (vfp) }, \ + .vback_porch = { (vbp), (vbp), (vbp) }, \ + .vsync_len = { (vsl), (vsl), (vsl) }, \ + .flags = (f) + +static const struct display_timing dmt_timings[] = { + { TIMING(31500000, 640, 32, 64, 96, 350, 32, 3, 60, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(31500000, 640, 32, 64, 96, 400, 1, 3, 41, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(35500000, 720, 36, 72, 108, 400, 1, 3, 42, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(25175000, 640, 16, 96, 48, 480, 10, 2, 33, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(31500000, 640, 24, 40, 128, 480, 9, 3, 28, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(31500000, 640, 16, 64, 120, 480, 1, 3, 16, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(36000000, 640, 56, 56, 80, 480, 1, 3, 25, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(36000000, 800, 24, 72, 128, 600, 1, 2, 22, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(40000000, 800, 40, 128, 88, 600, 1, 4, 23, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(50000000, 800, 56, 120, 64, 600, 37, 6, 23, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(49500000, 800, 16, 80, 160, 600, 1, 3, 21, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(56250000, 800, 32, 64, 152, 600, 1, 3, 27, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(73250000, 800, 48, 32, 80, 600, 3, 4, 29, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(33750000, 848, 16, 112, 112, 480, 6, 8, 23, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(44900000, 1024, 8, 176, 56, 768, 0, 8, 41, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(65000000, 1024, 24, 136, 160, 768, 3, 6, 29, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(75000000, 1024, 24, 136, 144, 768, 3, 6, 29, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(78750000, 1024, 16, 96, 176, 768, 1, 3, 28, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(94500000, 1024, 48, 96, 208, 768, 1, 3, 36, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(115500000, 1024, 48, 32, 80, 768, 3, 4, 38, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(108000000, 1152, 64, 128, 256, 864, 1, 3, 32, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(74250000, 1280, 110, 40, 220, 720, 5, 5, 20, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(68250000, 1280, 48, 32, 80, 768, 3, 7, 12, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(79500000, 1280, 64, 128, 192, 768, 3, 7, 20, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(102250000, 1280, 80, 128, 208, 768, 3, 7, 27, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(117500000, 1280, 80, 136, 216, 768, 3, 7, 31, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(140250000, 1280, 48, 32, 80, 768, 3, 7, 35, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(71000000, 1280, 48, 32, 80, 800, 3, 6, 14, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(83500000, 1280, 72, 128, 200, 800, 3, 6, 22, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(106500000, 1280, 80, 128, 208, 800, 3, 6, 29, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(122500000, 1280, 80, 136, 216, 800, 3, 6, 34, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(146250000, 1280, 48, 32, 80, 800, 3, 6, 38, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(108000000, 1280, 96, 112, 312, 960, 1, 3, 36, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(148500000, 1280, 64, 160, 224, 960, 1, 3, 47, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(175500000, 1280, 48, 32, 80, 960, 3, 4, 50, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(108000000, 1280, 48, 112, 248, 1024, 1, 3, 38, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(135000000, 1280, 16, 144, 248, 1024, 1, 3, 38, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(157500000, 1280, 64, 160, 224, 1024, 1, 3, 44, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(187250000, 1280, 48, 32, 80, 1024, 3, 7, 50, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(85500000, 1360, 64, 112, 256, 768, 3, 6, 18, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(148250000, 1360, 48, 32, 80, 768, 3, 5, 37, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(85500000, 1366, 70, 143, 213, 768, 3, 3, 24, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(72000000, 1366, 14, 56, 64, 768, 1, 3, 28, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(101000000, 1400, 48, 32, 80, 1050, 3, 4, 23, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(121750000, 1400, 88, 144, 232, 1050, 3, 4, 32, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(156000000, 1400, 104, 144, 248, 1050, 3, 4, 42, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(179500000, 1400, 104, 152, 256, 1050, 3, 4, 48, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(208000000, 1400, 48, 32, 80, 1050, 3, 4, 55, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(88750000, 1440, 48, 32, 80, 900, 3, 6, 17, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(106500000, 1440, 80, 152, 232, 900, 3, 6, 25, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(136750000, 1440, 96, 152, 248, 900, 3, 6, 33, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(157000000, 1440, 104, 152, 256, 900, 3, 6, 39, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(182750000, 1440, 48, 32, 80, 900, 3, 6, 44, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(108000000, 1600, 24, 80, 96, 900, 1, 3, 96, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(162000000, 1600, 64, 192, 304, 1200, 1, 3, 46, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(175500000, 1600, 64, 192, 304, 1200, 1, 3, 46, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(189000000, 1600, 64, 192, 304, 1200, 1, 3, 46, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(202500000, 1600, 64, 192, 304, 1200, 1, 3, 46, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(229500000, 1600, 64, 192, 304, 1200, 1, 3, 46, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(268250000, 1600, 48, 32, 80, 1200, 3, 4, 64, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(119000000, 1680, 48, 32, 80, 1050, 3, 6, 21, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(146250000, 1680, 104, 176, 280, 1050, 3, 6, 30, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(187000000, 1680, 120, 176, 296, 1050, 3, 6, 40, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(214750000, 1680, 128, 176, 304, 1050, 3, 6, 46, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(245500000, 1680, 48, 32, 80, 1050, 3, 6, 53, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(204750000, 1792, 128, 200, 328, 1344, 1, 3, 46, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(261000000, 1792, 96, 216, 352, 1344, 1, 3, 69, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(333250000, 1792, 48, 32, 80, 1344, 3, 4, 72, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(218250000, 1856, 96, 224, 352, 1392, 1, 3, 43, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(288000000, 1856, 128, 224, 352, 1392, 1, 3, 104, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(356500000, 1856, 48, 32, 80, 1392, 3, 4, 75, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(148500000, 1920, 88, 44, 148, 1080, 4, 5, 36, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(154000000, 1920, 48, 32, 80, 1200, 3, 6, 26, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(193250000, 1920, 136, 200, 336, 1200, 3, 6, 36, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(245250000, 1920, 136, 208, 344, 1200, 3, 6, 46, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(281250000, 1920, 144, 208, 352, 1200, 3, 6, 53, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(317000000, 1920, 48, 32, 80, 1200, 3, 6, 62, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(234000000, 1920, 128, 208, 344, 1440, 1, 3, 56, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(297000000, 1920, 144, 224, 352, 1440, 1, 3, 56, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(380500000, 1920, 48, 32, 80, 1440, 3, 4, 78, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(162000000, 2048, 26, 80, 96, 1152, 1, 3, 44, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(268500000, 2560, 48, 32, 80, 1600, 3, 6, 37, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(348500000, 2560, 192, 280, 472, 1600, 3, 6, 49, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(443250000, 2560, 208, 280, 488, 1600, 3, 6, 63, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(505250000, 2560, 208, 280, 488, 1600, 3, 6, 73, + DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH) }, + { TIMING(552750000, 2560, 48, 32, 80, 1600, 3, 6, 85, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(556744000, 4096, 8, 32, 40, 2160, 48, 8, 6, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, + { TIMING(556188000, 4096, 8, 32, 40, 2160, 48, 8, 6, + DISPLAY_FLAGS_HSYNC_HIGH | DISPLAY_FLAGS_VSYNC_LOW) }, +}; + int edid_check_info(struct edid1_info *edid_info) { if ((edid_info == NULL) || (edid_info->version == 0)) @@ -168,11 +359,11 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info) return false; } -static bool edid_find_valid_timing(void *buf, int count, - struct display_timing *timing, - bool (*mode_valid)(void *priv, - const struct display_timing *timing), - void *mode_valid_priv) +static bool edid_find_valid_detailed_timing(void *buf, int count, + struct display_timing *timing, + bool (*mode_valid)(void *priv, + const struct display_timing *timing), + void *mode_valid_priv) { struct edid_detailed_timing *t = buf; bool found = false; @@ -191,6 +382,71 @@ static bool edid_find_valid_timing(void *buf, int count, return found; } +static bool edid_get_standard_timing(struct edid1_info *edid, int i, unsigned int *x, + unsigned int *y, unsigned int *freq) +{ + unsigned int aspect = 10000; + unsigned char xres, vfreq; + + xres = EDID1_INFO_STANDARD_TIMING_XRESOLUTION(*edid, i); + vfreq = EDID1_INFO_STANDARD_TIMING_VFREQ(*edid, i); + if (xres != vfreq || (xres != 0 && xres != 1) || + (vfreq != 0 && vfreq != 1)) { + switch (EDID1_INFO_STANDARD_TIMING_ASPECT(*edid, i)) { + case ASPECT_625: // 16:10 + aspect = 6250; + break; + case ASPECT_75: // 4:3 + aspect = 7500; + break; + case ASPECT_8: // 5:4 + aspect = 8000; + break; + case ASPECT_5625: // 16:9 + aspect = 5625; + break; + } + + *x = (xres + 31) * 8; + *y = *x * aspect / 10000; + *freq = (vfreq & 0x3f) + 60; + + return true; + } + + return false; +} + +static bool edid_find_valid_standard_timing(struct edid1_info *buf, + struct display_timing *timing, + bool (*mode_valid)(void *priv, + const struct display_timing *timing), + void *mode_valid_priv) +{ + unsigned int x, y, freq; + bool found = false; + int i, k; + + for (i = 0; i < ARRAY_SIZE(buf->standard_timings); i++) { + if (!edid_get_standard_timing(buf, i, &x, &y, &freq)) + continue; + + for (k = 0; k < ARRAY_SIZE(dmt_timings); k++) { + const struct display_timing *dt = &dmt_timings[k]; + + if (dt->hactive.typ == x && dt->vactive.typ == y) { + found = mode_valid(mode_valid_priv, dt); + if (found) { + memcpy(timing, dt, sizeof(*timing)); + return true; + } + } + } + } + + return found; +} + int edid_get_timing_validate(u8 *buf, int buf_size, struct display_timing *timing, int *panel_bits_per_colourp, @@ -217,8 +473,8 @@ int edid_get_timing_validate(u8 *buf, int buf_size, } /* Look for detailed timing in base EDID */ - found = edid_find_valid_timing(edid->monitor_details.descriptor, 4, - timing, mode_valid, mode_valid_priv); + found = edid_find_valid_detailed_timing(edid->monitor_details.descriptor, 4, + timing, mode_valid, mode_valid_priv); /* Look for detailed timing in CTA-861 Extension Block */ if (!found && edid->extension_flag && buf_size >= EDID_EXT_SIZE) { @@ -231,12 +487,17 @@ int edid_get_timing_validate(u8 *buf, int buf_size, int size = count * sizeof(struct edid_detailed_timing); if (offset >= 4 && offset + size < EDID_SIZE) - found = edid_find_valid_timing( + found = edid_find_valid_detailed_timing( (u8 *)info + offset, count, timing, mode_valid, mode_valid_priv); } } + /* Look for timing in Standard Timings */ + if (!found) + found = edid_find_valid_standard_timing(edid, timing, mode_valid, + mode_valid_priv); + if (!found) return -EINVAL; @@ -461,34 +722,11 @@ void edid_print_info(struct edid1_info *edid_info) /* Standard timings. */ printf("Standard timings:\n"); for (i = 0; i < ARRAY_SIZE(edid_info->standard_timings); i++) { - unsigned int aspect = 10000; - unsigned int x, y; - unsigned char xres, vfreq; - - xres = EDID1_INFO_STANDARD_TIMING_XRESOLUTION(*edid_info, i); - vfreq = EDID1_INFO_STANDARD_TIMING_VFREQ(*edid_info, i); - if ((xres != vfreq) || - ((xres != 0) && (xres != 1)) || - ((vfreq != 0) && (vfreq != 1))) { - switch (EDID1_INFO_STANDARD_TIMING_ASPECT(*edid_info, - i)) { - case ASPECT_625: - aspect = 6250; - break; - case ASPECT_75: - aspect = 7500; - break; - case ASPECT_8: - aspect = 8000; - break; - case ASPECT_5625: - aspect = 5625; - break; - } - x = (xres + 31) * 8; - y = x * aspect / 10000; + unsigned int x, y, freq; + + if (edid_get_standard_timing(edid_info, i, &x, &y, &freq)) { printf("\t%dx%d%c\t%d Hz\n", x, y, - x > 1000 ? ' ' : '\t', (vfreq & 0x3f) + 60); + x > 1000 ? ' ' : '\t', freq); have_timing = 1; } } diff --git a/configs/endeavoru_defconfig b/configs/endeavoru_defconfig index 1d1f1042291..cc8777e4d83 100644 --- a/configs/endeavoru_defconfig +++ b/configs/endeavoru_defconfig @@ -21,7 +21,7 @@ CONFIG_AUTOBOOT_KEYED=y CONFIG_AUTOBOOT_KEYED_CTRLC=y CONFIG_OF_BOARD_SETUP=y CONFIG_OF_SYSTEM_SETUP=y -CONFIG_BOOTCOMMAND="bootflow scan; poweroff" +CONFIG_BOOTCOMMAND="bootflow scan; echo 'Boot configuration not found... Power off in 3 sec'; sleep 3; poweroff" CONFIG_SYS_PBSIZE=2084 CONFIG_SPL_FOOTPRINT_LIMIT=y CONFIG_SPL_MAX_FOOTPRINT=0x8000 diff --git a/configs/grouper_defconfig b/configs/grouper_defconfig index 9221ffb46a3..f265db8232f 100644 --- a/configs/grouper_defconfig +++ b/configs/grouper_defconfig @@ -21,7 +21,7 @@ CONFIG_AUTOBOOT_KEYED=y CONFIG_AUTOBOOT_KEYED_CTRLC=y CONFIG_OF_BOARD_SETUP=y CONFIG_OF_SYSTEM_SETUP=y -CONFIG_BOOTCOMMAND="bootflow scan; poweroff" +CONFIG_BOOTCOMMAND="bootflow scan; echo 'Boot configuration not found... Power off in 3 sec'; sleep 3; poweroff" CONFIG_SYS_PBSIZE=2084 CONFIG_SPL_FOOTPRINT_LIMIT=y CONFIG_SPL_MAX_FOOTPRINT=0x8000 diff --git a/configs/mocha_defconfig b/configs/mocha_defconfig new file mode 100644 index 00000000000..0cbedb21797 --- /dev/null +++ b/configs/mocha_defconfig @@ -0,0 +1,91 @@ +CONFIG_ARM=y +CONFIG_ARCH_TEGRA=y +CONFIG_SUPPORT_PASSING_ATAGS=y +CONFIG_CMDLINE_TAG=y +CONFIG_INITRD_TAG=y +CONFIG_TEXT_BASE=0x80110000 +CONFIG_SYS_MALLOC_LEN=0x2500000 +CONFIG_NR_DRAM_BANKS=2 +CONFIG_ENV_SOURCE_FILE="mocha" +CONFIG_ENV_SIZE=0x3000 +CONFIG_ENV_OFFSET=0xFFFFD000 +CONFIG_DEFAULT_DEVICE_TREE="tegra124-xiaomi-mocha" +CONFIG_SPL_STACK=0x800ffffc +CONFIG_SPL_TEXT_BASE=0x80108000 +CONFIG_SYS_LOAD_ADDR=0x82000000 +CONFIG_TEGRA124=y +CONFIG_TARGET_MOCHA=y +CONFIG_TEGRA_ENABLE_UARTD=y +CONFIG_CMD_EBTUPDATE=y +CONFIG_TEGRA_GPU=y +CONFIG_BUTTON_CMD=y +CONFIG_BOOTDELAY=0 +CONFIG_AUTOBOOT_KEYED=y +CONFIG_AUTOBOOT_KEYED_CTRLC=y +CONFIG_OF_SYSTEM_SETUP=y +CONFIG_BOOTCOMMAND="bootflow scan; echo 'Boot configuration not found... Power off in 3 sec'; sleep 3; poweroff" +CONFIG_SYS_PBSIZE=2086 +CONFIG_SPL_FOOTPRINT_LIMIT=y +CONFIG_SPL_MAX_FOOTPRINT=0x8000 +# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set +CONFIG_SPL_SYS_MALLOC=y +CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y +CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x80090000 +CONFIG_SPL_SYS_MALLOC_SIZE=0x10000 +CONFIG_SYS_PROMPT="Tegra124 (Mocha) # " +# CONFIG_CMD_BOOTEFI_BOOTMGR is not set +CONFIG_CMD_BOOTMENU=y +# CONFIG_CMD_IMI is not set +CONFIG_CMD_GPIO=y +CONFIG_CMD_GPT=y +CONFIG_CMD_GPT_RENAME=y +CONFIG_CMD_I2C=y +CONFIG_CMD_MMC=y +CONFIG_CMD_POWEROFF=y +CONFIG_CMD_USB=y +CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_UMS_ABORT_KEYED=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_PAUSE=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_EXT4_WRITE=y +# CONFIG_SPL_DOS_PARTITION is not set +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_ENV_OVERWRITE=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_SYS_MMC_ENV_PART=2 +CONFIG_BUTTON=y +CONFIG_USB_FUNCTION_FASTBOOT=y +CONFIG_FASTBOOT_BUF_ADDR=0x91000000 +CONFIG_FASTBOOT_BUF_SIZE=0x10000000 +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=0 +CONFIG_FASTBOOT_CMD_OEM_FORMAT=y +CONFIG_PALMAS_GPIO=y +CONFIG_SYS_I2C_TEGRA=y +CONFIG_BUTTON_KEYBOARD=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_PALMAS=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_DM_REGULATOR_PALMAS=y +CONFIG_PWM_TEGRA=y +CONFIG_SYS_NS16550=y +CONFIG_SYSRESET_PALMAS=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_TEGRA=y +CONFIG_USB_KEYBOARD=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_MANUFACTURER="Xiaomi" +CONFIG_USB_GADGET_VENDOR_NUM=0x18d1 +CONFIG_USB_GADGET_PRODUCT_NUM=0xd00d +CONFIG_CI_UDC=y +CONFIG_VIDEO=y +CONFIG_VIDEO_BRIDGE=y +# CONFIG_VIDEO_FONT_8X16 is not set +CONFIG_VIDEO_FONT_16X32=y +# CONFIG_VIDEO_LOGO is not set +CONFIG_VIDEO_LCD_SHARP_LQ079L1SX01=y +CONFIG_BACKLIGHT_LP855x=y +CONFIG_VIDEO_DSI_TEGRA30=y diff --git a/configs/picasso_defconfig b/configs/picasso_defconfig index 994951bb81e..a9b7f91b735 100644 --- a/configs/picasso_defconfig +++ b/configs/picasso_defconfig @@ -21,7 +21,7 @@ CONFIG_BOOTDELAY=0 CONFIG_AUTOBOOT_KEYED=y CONFIG_AUTOBOOT_KEYED_CTRLC=y CONFIG_OF_SYSTEM_SETUP=y -CONFIG_BOOTCOMMAND="bootflow scan; poweroff" +CONFIG_BOOTCOMMAND="bootflow scan; echo 'Boot configuration not found... Power off in 3 sec'; sleep 3; poweroff" CONFIG_SYS_PBSIZE=2085 CONFIG_SPL_FOOTPRINT_LIMIT=y CONFIG_SPL_MAX_FOOTPRINT=0x8000 diff --git a/configs/qc750_defconfig b/configs/qc750_defconfig index 2485e64a2f0..e958e0d53ca 100644 --- a/configs/qc750_defconfig +++ b/configs/qc750_defconfig @@ -22,7 +22,7 @@ CONFIG_AUTOBOOT_KEYED=y CONFIG_AUTOBOOT_KEYED_CTRLC=y CONFIG_OF_BOARD_SETUP=y CONFIG_OF_SYSTEM_SETUP=y -CONFIG_BOOTCOMMAND="bootflow scan; poweroff" +CONFIG_BOOTCOMMAND="bootflow scan; echo 'Boot configuration not found... Power off in 3 sec'; sleep 3; poweroff" CONFIG_SYS_PBSIZE=2084 CONFIG_SPL_FOOTPRINT_LIMIT=y CONFIG_SPL_MAX_FOOTPRINT=0x8000 diff --git a/configs/transformer_t20_defconfig b/configs/transformer_t20_defconfig index b69366581a4..6f823ec720e 100644 --- a/configs/transformer_t20_defconfig +++ b/configs/transformer_t20_defconfig @@ -21,7 +21,7 @@ CONFIG_BOOTDELAY=0 CONFIG_AUTOBOOT_KEYED=y CONFIG_AUTOBOOT_KEYED_CTRLC=y CONFIG_OF_SYSTEM_SETUP=y -CONFIG_BOOTCOMMAND="bootflow scan; poweroff" +CONFIG_BOOTCOMMAND="bootflow scan; echo 'Boot configuration not found... Power off in 3 sec'; sleep 3; poweroff" CONFIG_SYS_PBSIZE=2085 CONFIG_SPL_FOOTPRINT_LIMIT=y CONFIG_SPL_MAX_FOOTPRINT=0x8000 diff --git a/configs/transformer_t30_defconfig b/configs/transformer_t30_defconfig index c5f0bc2a613..9d63755533a 100644 --- a/configs/transformer_t30_defconfig +++ b/configs/transformer_t30_defconfig @@ -21,7 +21,7 @@ CONFIG_AUTOBOOT_KEYED=y CONFIG_AUTOBOOT_KEYED_CTRLC=y CONFIG_OF_BOARD_SETUP=y CONFIG_OF_SYSTEM_SETUP=y -CONFIG_BOOTCOMMAND="bootflow scan; poweroff" +CONFIG_BOOTCOMMAND="bootflow scan; echo 'Boot configuration not found... Power off in 3 sec'; sleep 3; poweroff" CONFIG_SYS_PBSIZE=2084 CONFIG_SPL_FOOTPRINT_LIMIT=y CONFIG_SPL_MAX_FOOTPRINT=0x8000 diff --git a/configs/x3_t30_defconfig b/configs/x3_t30_defconfig index c8da5b4ce35..2d72a3bd56f 100644 --- a/configs/x3_t30_defconfig +++ b/configs/x3_t30_defconfig @@ -21,7 +21,7 @@ CONFIG_AUTOBOOT_KEYED=y CONFIG_AUTOBOOT_KEYED_CTRLC=y CONFIG_OF_BOARD_SETUP=y CONFIG_OF_SYSTEM_SETUP=y -CONFIG_BOOTCOMMAND="bootflow scan; poweroff" +CONFIG_BOOTCOMMAND="bootflow scan; echo 'Boot configuration not found... Power off in 3 sec'; sleep 3; poweroff" CONFIG_SYS_PBSIZE=2084 CONFIG_SPL_FOOTPRINT_LIMIT=y CONFIG_SPL_MAX_FOOTPRINT=0x8000 diff --git a/doc/board/index.rst b/doc/board/index.rst index b055046e649..84c135e02c1 100644 --- a/doc/board/index.rst +++ b/doc/board/index.rst @@ -69,4 +69,5 @@ Board-specific doc variscite/index wexler/index xen/index + xiaomi/index xilinx/index diff --git a/doc/board/xiaomi/index.rst b/doc/board/xiaomi/index.rst new file mode 100644 index 00000000000..109ab4a251f --- /dev/null +++ b/doc/board/xiaomi/index.rst @@ -0,0 +1,9 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Xiaomi +====== + +.. toctree:: + :maxdepth: 2 + + mocha diff --git a/doc/board/xiaomi/mocha.rst b/doc/board/xiaomi/mocha.rst new file mode 100644 index 00000000000..be3e333127b --- /dev/null +++ b/doc/board/xiaomi/mocha.rst @@ -0,0 +1,112 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +U-Boot for the Xiaomi Mi Pad tablet +=================================== + +``DISCLAMER!`` Moving your Xiaomi Mi Pad to use U-Boot assumes replacement +of the vendor bootloader. Vendor Android firmwares will no longer be able +to run on the device. This replacement IS reversible. + +Quick Start +----------- + +- Build U-Boot +- Boot U-Boot +- Process and flash U-Boot +- Boot Linux +- Self Upgrading +- Chainload configuration + +Build U-Boot +------------ + +.. code-block:: bash + + $ export CROSS_COMPILE=arm-none-eabi- + $ make mocha_defconfig + $ make + +After the build succeeds, you will obtain the final ``u-boot-dtb-tegra.bin`` +image, ready for booting or further processing. + +Boot U-Boot +----------- +Existing tegrarcm loader can be used to pre-load U-Boot you have build +into RAM and basically perform a tethered cold-boot. + +.. code-block:: bash + + $ tegrarcm --bct mocha.bct --bootloader u-boot-dtb-tegra.bin --loadaddr 0x80108000 + +U-Boot will try to load Linux kernel and if fails, it will turn the +tablet off. While pre-loading U-Boot, hold the ``volume down`` button +which will trigger the bootmenu. + +Process and flash U-Boot +------------------------ + +``DISCLAMER!`` All questions related to the re-crypt work should be asked +in re-crypt repo issues. NOT HERE! + +re-crypt is a tool that processes the ``u-boot-dtb-tegra.bin`` binary into +form usable by device. This process is required only on the first +installation or to recover the device in case of a failed update. + +.. code-block:: bash + + $ git clone https://gitlab.com/grate-driver/re-crypt.git + $ cd re-crypt # place your u-boot-dtb-tegra.bin here + $ ./re-crypt.py --dev mocha + +The script will produce ``bct.img`` and ``ebt.img`` ready to flash. + +Permanent installation can be performed by pre-loading just built U-Boot +into RAM via tegrarcm. While pre-loading U-Boot, hold the ``volume down`` +button which will trigger the bootmenu. There, select ``fastboot`` using +the volume and power buttons. + +After, on host PC, do: + +.. code-block:: bash + + $ fastboot flash 0.1 bct.img + $ fastboot flash 0.2 ebt.img + $ fastboot reboot + +Device will reboot. + +Boot Linux +---------- + +To boot Linux, U-Boot will look for an ``extlinux.conf`` on MicroSD and then on +eMMC. Additionally, if the ``volume down`` button is pressed while booting, the +device will enter bootmenu. Bootmenu contains entries to mount MicroSD and eMMC +as mass storage, fastboot, reboot, reboot RCM, poweroff, enter U-Boot console +and update bootloader (check the next chapter). + +Flashing ``bct.img`` and ``ebt.img`` eliminates vendor restrictions on eMMC and +allows the user to use/partition it in any way the user desires. + +Self Upgrading +-------------- + +Place your ``u-boot-dtb-tegra.bin`` on the first partition of the MicroSD card +and insert it into the tablet. Enter bootmenu, choose update the bootloader +option with the Power button and U-Boot should update itself. Once the process +is completed, U-Boot will ask to press any button to reboot. + +Chainload configuration +----------------------- + +To build U-Boot without SPL suitable for chainloading adjust mocha_defconfig: + +.. code-block:: + + CONFIG_TEXT_BASE=0x80A00000 + CONFIG_SKIP_LOWLEVEL_INIT=y + # CONFIG_OF_BOARD_SETUP is not set + CONFIG_TEGRA_SUPPORT_NON_SECURE=y + +After the build succeeds, you will obtain the final ``u-boot-dtb.bin`` +file, ready for booting using vendor bootloader's fastboot or which can be +further processed into a flashable image. diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c index ad7112a05e6..e6b957f5537 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra.c @@ -67,6 +67,58 @@ exit: kfree(drive_group); } +#ifdef TEGRA_PMX_SOC_HAS_MIPI_PAD_CTRL_GRPS +static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt) +{ + struct pmux_mipipadctrlgrp_config *mipipad_group; + int i, ret, pad_id; + const char *function; + const char **pads; + + mipipad_group = kmalloc_array(padcnt, sizeof(*mipipad_group), GFP_KERNEL); + if (!mipipad_group) { + log_debug("%s: cannot allocate mipi pad group array\n", __func__); + return; + } + + /* decode function id and fill the first copy of pmux_mipipadctrlgrp_config */ + function = dev_read_string(config, "nvidia,function"); + if (function) + for (i = 0; i < PMUX_FUNC_COUNT; i++) + if (tegra_pinctrl_to_func[i]) + if (!strcmp(function, tegra_pinctrl_to_func[i])) + break; + + mipipad_group[0].func = i; + + for (i = 1; i < padcnt; i++) + memcpy(&mipipad_group[i], &mipipad_group[0], sizeof(mipipad_group[0])); + + ret = dev_read_string_list(config, "nvidia,pins", &pads); + if (ret < 0) { + log_debug("%s: could not parse property nvidia,pins\n", __func__); + goto exit; + } + + for (i = 0; i < padcnt; i++) { + for (pad_id = 0; pad_id < PMUX_MIPIPADCTRLGRP_COUNT; pad_id++) + if (tegra_pinctrl_to_mipipadgrp[pad_id]) + if (!strcmp(pads[i], tegra_pinctrl_to_mipipadgrp[pad_id])) { + mipipad_group[i].grp = pad_id; + break; + } + } + + pinmux_config_mipipadctrlgrp_table(mipipad_group, padcnt); + + free(pads); +exit: + kfree(mipipad_group); +} +#else +static void tegra_pinctrl_set_mipipad(struct udevice *config, int padcnt) { } +#endif + static void tegra_pinctrl_set_pin(struct udevice *config, int pincnt) { struct pmux_pingrp_config *pinmux_group; @@ -170,6 +222,9 @@ static int tegra_pinctrl_set_state(struct udevice *dev, struct udevice *config) if (!strncmp(name, "drive_", 6)) /* Drive node is detected */ tegra_pinctrl_set_drive(child, ret); + else if (!strncmp(name, "mipi_pad_ctrl_", 14)) + /* Handle T124 specific pinconfig */ + tegra_pinctrl_set_mipipad(child, ret); else /* Pin node is detected */ tegra_pinctrl_set_pin(child, ret); @@ -236,6 +291,7 @@ static int tegra_pinctrl_bind(struct udevice *dev) static const struct udevice_id tegra_pinctrl_ids[] = { { .compatible = "nvidia,tegra30-pinmux" }, { .compatible = "nvidia,tegra114-pinmux" }, + { .compatible = "nvidia,tegra124-pinmux" }, { }, }; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3c3cebaacd0..b1ef73f3e5c 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -599,6 +599,15 @@ config VIDEO_LCD_SAMSUNG_LTL106HL02 LCD module found in Microsoft Surface 2. The panel has a FullHD resolution (1920x1080). +config VIDEO_LCD_SHARP_LQ079L1SX01 + tristate "Sharp LQ079L1SX01 1536x2048 DSI video mode panel" + depends on PANEL && BACKLIGHT + select VIDEO_MIPI_DSI + help + Say Y here if you want to enable support for Sharp LQ079L1SX01 + LCD module found in Xiaomi Mi Pad tablet. The panel has a QXGA + resolution (1536x2048). + config VIDEO_LCD_SHARP_LQ101R1SX01 tristate "Sharp LQ101R1SX01 2560x1600 DSI video mode panel" depends on PANEL && BACKLIGHT @@ -743,6 +752,16 @@ config BACKLIGHT_LM3533 LM3533 Lighting Power chip. Only Bank A is supported as for now. Supported backlight level range is from 2 to 255 with step of 1. +config BACKLIGHT_LP855x + bool "Backlight Driver for LP855x" + depends on BACKLIGHT + select DM_I2C + help + Say Y to enable the backlight driver for National Semiconductor / TI + LP8550/1/2/3/5/6/7 LED Backlight Driver. Only register driven mode is + supported for now, PWM mode can be added if there will be any need in + it. Supported backlight level range is from 0 to 255 with step of 1. + source "drivers/video/ti/Kconfig" source "drivers/video/exynos/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 5a00438ce06..6073bc5234a 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_$(PHASE_)BMP) += bmp.o endif obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_backlight.o +obj-$(CONFIG_BACKLIGHT_LP855x) += lp855x_backlight.o obj-${CONFIG_EXYNOS_FB} += exynos/ obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/ obj-${CONFIG_VIDEO_STM32} += stm32/ @@ -64,6 +65,7 @@ obj-$(CONFIG_VIDEO_LCD_RAYDIUM_RM68200) += raydium-rm68200.o obj-$(CONFIG_VIDEO_LCD_RENESAS_R61307) += renesas-r61307.o obj-$(CONFIG_VIDEO_LCD_RENESAS_R69328) += renesas-r69328.o obj-$(CONFIG_VIDEO_LCD_SAMSUNG_LTL106HL02) += samsung-ltl106hl02.o +obj-$(CONFIG_VIDEO_LCD_SHARP_LQ079L1SX01) += sharp-lq079l1sx01.o obj-$(CONFIG_VIDEO_LCD_SHARP_LQ101R1SX01) += sharp-lq101r1sx01.o obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o obj-$(CONFIG_VIDEO_LCD_TDO_TL070WSH30) += tdo-tl070wsh30.o diff --git a/drivers/video/lp855x_backlight.c b/drivers/video/lp855x_backlight.c new file mode 100644 index 00000000000..5debc0aa453 --- /dev/null +++ b/drivers/video/lp855x_backlight.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2011 Texas Instruments + * Copyright (c) 2024 Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT + +#include <malloc.h> +#include <backlight.h> +#include <dm.h> +#include <dm/devres.h> +#include <i2c.h> +#include <log.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <asm/gpio.h> +#include <power/regulator.h> + +#define LP855x_MIN_BRIGHTNESS 0x00 +#define LP855x_MAX_BRIGHTNESS 0xff + +/* LP8550/1/2/3/6 Registers */ +#define LP855X_BRIGHTNESS_CTRL 0x00 +#define LP855X_DEVICE_CTRL 0x01 +#define LP855X_EEPROM_START 0xa0 +#define LP855X_EEPROM_END 0xa7 +#define LP8556_EPROM_START 0x98 +#define LP8556_EPROM_END 0xaf + +/* LP8555/7 Registers */ +#define LP8557_BL_CMD 0x00 +#define LP8557_BL_MASK 0x01 +#define LP8557_BL_ON 0x01 +#define LP8557_BL_OFF 0x00 +#define LP8557_BRIGHTNESS_CTRL 0x04 +#define LP8557_CONFIG 0x10 +#define LP8555_EPROM_START 0x10 +#define LP8555_EPROM_END 0x7a +#define LP8557_EPROM_START 0x10 +#define LP8557_EPROM_END 0x1e + +struct lp855x_rom_data { + u8 addr; + u8 val; +}; + +struct lp855x_backlight_priv; + +/* + * struct lp855x_device_config + * @pre_init_device: init device function call before updating the brightness + * @reg_brightness: register address for brigthenss control + * @reg_devicectrl: register address for device control + * @post_init_device: late init device function call + */ +struct lp855x_device_config { + int (*pre_init_device)(struct udevice *dev); + u8 reg_brightness; + u8 reg_devicectrl; + u8 reg_eepromstart; + u8 reg_eepromend; + int (*post_init_device)(struct udevice *dev); +}; + +struct lp855x_backlight_priv { + struct udevice *supply; /* regulator for VDD input */ + struct udevice *enable; /* regulator for EN/VDDIO input */ + + u8 device_control; + u8 initial_brightness; + + int size_program; + struct lp855x_rom_data *rom_data; + struct lp855x_device_config *cfg; +}; + +static int lp855x_backlight_enable(struct udevice *dev) +{ + struct lp855x_backlight_priv *priv = dev_get_priv(dev); + int ret; + + ret = regulator_set_enable_if_allowed(priv->supply, 1); + if (ret) { + log_debug("%s: enabling power-supply failed (%d)\n", + __func__, ret); + return ret; + } + + ret = regulator_set_enable_if_allowed(priv->enable, 1); + if (ret) { + log_debug("%s: enabling enable-supply failed (%d)\n", + __func__, ret); + return ret; + } + mdelay(2); + + if (priv->cfg->pre_init_device) { + ret = priv->cfg->pre_init_device(dev); + if (ret) { + log_debug("%s: pre init device err: %d\n", + __func__, ret); + return ret; + } + } + + ret = dm_i2c_reg_write(dev, priv->cfg->reg_brightness, + priv->initial_brightness); + if (ret) + return ret; + + ret = dm_i2c_reg_write(dev, priv->cfg->reg_devicectrl, + priv->device_control); + if (ret) + return ret; + + if (priv->size_program > 0) { + int i; + u8 val, addr; + + for (i = 0; i < priv->size_program; i++) { + addr = priv->rom_data[i].addr; + val = priv->rom_data[i].val; + + if (addr < priv->cfg->reg_eepromstart && + addr > priv->cfg->reg_eepromend) + continue; + + ret = dm_i2c_reg_write(dev, addr, val); + if (ret) + return ret; + } + } + + if (priv->cfg->post_init_device) { + ret = priv->cfg->post_init_device(dev); + if (ret) { + log_debug("%s: post init device err: %d\n", + __func__, ret); + return ret; + } + } + + return 0; +} + +static int lp855x_backlight_set_brightness(struct udevice *dev, int percent) +{ + struct lp855x_backlight_priv *priv = dev_get_priv(dev); + + if (percent == BACKLIGHT_DEFAULT) + percent = priv->initial_brightness; + + if (percent < LP855x_MIN_BRIGHTNESS) + percent = LP855x_MIN_BRIGHTNESS; + + if (percent > LP855x_MAX_BRIGHTNESS) + percent = LP855x_MAX_BRIGHTNESS; + + /* Set brightness level */ + return dm_i2c_reg_write(dev, priv->cfg->reg_brightness, + percent); +} + +static int lp855x_backlight_probe(struct udevice *dev) +{ + struct lp855x_backlight_priv *priv = dev_get_priv(dev); + int rom_length, ret; + + if (device_get_uclass_id(dev->parent) != UCLASS_I2C) + return -EPROTONOSUPPORT; + + priv->cfg = (struct lp855x_device_config *)dev_get_driver_data(dev); + + dev_read_u8(dev, "dev-ctrl", &priv->device_control); + dev_read_u8(dev, "init-brt", &priv->initial_brightness); + + /* Fill ROM platform data if defined */ + rom_length = dev_get_child_count(dev); + if (rom_length > 0) { + struct lp855x_rom_data *rom; + ofnode child; + int i = 0; + + rom = devm_kcalloc(dev, rom_length, sizeof(*rom), GFP_KERNEL); + if (!rom) + return -ENOMEM; + + dev_for_each_subnode(child, dev) { + ofnode_read_u8(child, "rom-addr", &rom[i].addr); + ofnode_read_u8(child, "rom-val", &rom[i].val); + i++; + } + + priv->size_program = rom_length; + priv->rom_data = &rom[0]; + } + + ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, + "power-supply", &priv->supply); + if (ret) { + log_err("%s: cannot get power-supply: ret = %d\n", __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, + "enable-supply", &priv->enable); + if (ret) { + log_err("%s: cannot get enable-supply: ret = %d\n", __func__, ret); + return ret; + } + + return 0; +} + +static const struct backlight_ops lp855x_backlight_ops = { + .enable = lp855x_backlight_enable, + .set_brightness = lp855x_backlight_set_brightness, +}; + +static int lp8556_bl_rst(struct udevice *dev) +{ + int ret; + + /* Reset backlight after updating EPROM settings */ + ret = dm_i2c_reg_clrset(dev, LP855X_DEVICE_CTRL, LP8557_BL_MASK, + LP8557_BL_OFF); + if (ret) + return ret; + + mdelay(10); + + return dm_i2c_reg_clrset(dev, LP855X_DEVICE_CTRL, LP8557_BL_MASK, + LP8557_BL_ON); +} + +static int lp8557_bl_off(struct udevice *dev) +{ + /* BL_ON = 0 before updating EPROM settings */ + return dm_i2c_reg_clrset(dev, LP8557_BL_CMD, LP8557_BL_MASK, + LP8557_BL_OFF); +} + +static int lp8557_bl_on(struct udevice *dev) +{ + /* BL_ON = 1 after updating EPROM settings */ + return dm_i2c_reg_clrset(dev, LP8557_BL_CMD, LP8557_BL_MASK, + LP8557_BL_ON); +} + +static struct lp855x_device_config lp855x_dev_cfg = { + .reg_brightness = LP855X_BRIGHTNESS_CTRL, + .reg_devicectrl = LP855X_DEVICE_CTRL, + .reg_eepromstart = LP855X_EEPROM_START, + .reg_eepromend = LP855X_EEPROM_END, +}; + +static struct lp855x_device_config lp8555_dev_cfg = { + .reg_brightness = LP8557_BRIGHTNESS_CTRL, + .reg_devicectrl = LP8557_CONFIG, + .reg_eepromstart = LP8555_EPROM_START, + .reg_eepromend = LP8555_EPROM_END, + .pre_init_device = lp8557_bl_off, + .post_init_device = lp8557_bl_on, +}; + +static struct lp855x_device_config lp8556_dev_cfg = { + .reg_brightness = LP855X_BRIGHTNESS_CTRL, + .reg_devicectrl = LP855X_DEVICE_CTRL, + .reg_eepromstart = LP8556_EPROM_START, + .reg_eepromend = LP8556_EPROM_END, + .post_init_device = lp8556_bl_rst, +}; + +static struct lp855x_device_config lp8557_dev_cfg = { + .reg_brightness = LP8557_BRIGHTNESS_CTRL, + .reg_devicectrl = LP8557_CONFIG, + .reg_eepromstart = LP8557_EPROM_START, + .reg_eepromend = LP8557_EPROM_END, + .pre_init_device = lp8557_bl_off, + .post_init_device = lp8557_bl_on, +}; + +static const struct udevice_id lp855x_backlight_ids[] = { + { .compatible = "ti,lp8550", .data = (ulong)&lp855x_dev_cfg }, + { .compatible = "ti,lp8551", .data = (ulong)&lp855x_dev_cfg }, + { .compatible = "ti,lp8552", .data = (ulong)&lp855x_dev_cfg }, + { .compatible = "ti,lp8553", .data = (ulong)&lp855x_dev_cfg }, + { .compatible = "ti,lp8555", .data = (ulong)&lp8555_dev_cfg }, + { .compatible = "ti,lp8556", .data = (ulong)&lp8556_dev_cfg }, + { .compatible = "ti,lp8557", .data = (ulong)&lp8557_dev_cfg }, + { } +}; + +U_BOOT_DRIVER(lp855x_backlight) = { + .name = "lp855x_backlight", + .id = UCLASS_PANEL_BACKLIGHT, + .of_match = lp855x_backlight_ids, + .probe = lp855x_backlight_probe, + .ops = &lp855x_backlight_ops, + .priv_auto = sizeof(struct lp855x_backlight_priv), +}; diff --git a/drivers/video/sharp-lq079l1sx01.c b/drivers/video/sharp-lq079l1sx01.c new file mode 100644 index 00000000000..a8197f40fc7 --- /dev/null +++ b/drivers/video/sharp-lq079l1sx01.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Sharp LQ079L1SX01 DSI panel driver + * + * Copyright (c) 2024 Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#include <backlight.h> +#include <dm.h> +#include <panel.h> +#include <log.h> +#include <mipi_dsi.h> +#include <linux/delay.h> +#include <asm/gpio.h> +#include <power/regulator.h> + +struct sharp_lq079l1sx01_priv { + struct udevice *backlight; + struct udevice *panel_sec; + + struct udevice *avdd; + struct udevice *vddio; + struct udevice *vsp; + struct udevice *vsn; + + struct gpio_desc reset_gpio; +}; + +static struct display_timing default_timing = { + .pixelclock.typ = 215000000, + .hactive.typ = 1536, + .hfront_porch.typ = 136, + .hback_porch.typ = 28, + .hsync_len.typ = 28, + .vactive.typ = 2048, + .vfront_porch.typ = 14, + .vback_porch.typ = 8, + .vsync_len.typ = 2, +}; + +static int dcs_write_one(struct mipi_dsi_device *dsi, u8 cmd, u8 data) +{ + return mipi_dsi_dcs_write(dsi, cmd, &data, 1); +} + +static int sharp_lq079l1sx01_configure_link(struct udevice *dev) +{ + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); + struct mipi_dsi_device *dsi = plat->device; + int ret; + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + log_debug("%s: failed to exit sleep mode %s: %d\n", + __func__, dev->parent->name, ret); + } + mdelay(120); + + ret = dcs_write_one(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0xff); + if (ret < 0) { + log_debug("%s: failed to SET_DISPLAY_BRIGHTNESS %s: %d\n", + __func__, dev->parent->name, ret); + } + ret = dcs_write_one(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x01); + if (ret < 0) { + log_debug("%s: failed to WRITE_POWER_SAVE %s: %d\n", + __func__, dev->parent->name, ret); + } + ret = dcs_write_one(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x2c); + if (ret < 0) { + log_debug("%s: failed to WRITE_CONTROL_DISPLAY %s: %d\n", + __func__, dev->parent->name, ret); + } + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + log_debug("%s: failed to set panel on %s: %d\n", + __func__, dev->parent->name, ret); + } + + return 0; +} + +static int sharp_lq079l1sx01_enable_backlight(struct udevice *dev) +{ + struct sharp_lq079l1sx01_priv *priv = dev_get_priv(dev); + + if (!priv->panel_sec) + return 0; + + sharp_lq079l1sx01_configure_link(dev); + sharp_lq079l1sx01_configure_link(priv->panel_sec); + + return 0; +} + +static int sharp_lq079l1sx01_set_backlight(struct udevice *dev, int percent) +{ + struct sharp_lq079l1sx01_priv *priv = dev_get_priv(dev); + int ret; + + if (!priv->panel_sec) + return 0; + + ret = backlight_enable(priv->backlight); + if (ret) + return ret; + + return backlight_set_brightness(priv->backlight, percent); +} + +static int sharp_lq079l1sx01_timings(struct udevice *dev, + struct display_timing *timing) +{ + memcpy(timing, &default_timing, sizeof(*timing)); + return 0; +} + +static int sharp_lq079l1sx01_of_to_plat(struct udevice *dev) +{ + struct sharp_lq079l1sx01_priv *priv = dev_get_priv(dev); + int ret; + + /* If node has no link2 it is secondary panel */ + if (!dev_read_bool(dev, "link2")) + return 0; + + ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, + "link2", &priv->panel_sec); + if (ret) { + log_debug("%s: cannot get secondary panel: ret = %d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, + "backlight", &priv->backlight); + if (ret) { + log_debug("%s: cannot get backlight: ret = %d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, + "avdd-supply", &priv->avdd); + if (ret) { + log_debug("%s: cannot get avdd-supply: ret = %d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, + "vddio-supply", &priv->vddio); + if (ret) { + log_debug("%s: cannot get vddio-supply: ret = %d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, + "vsp-supply", &priv->vsp); + if (ret) { + log_debug("%s: cannot get vsp-supply: ret = %d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, + "vsn-supply", &priv->vsn); + if (ret) { + log_debug("%s: cannot get vsn-supply: ret = %d\n", + __func__, ret); + return ret; + } + + ret = gpio_request_by_name(dev, "reset-gpios", 0, + &priv->reset_gpio, GPIOD_IS_OUT); + if (ret) { + log_debug("%s: cannot get reser-gpios (%d)\n", + __func__, ret); + return ret; + } + + return 0; +} + +static int sharp_lq079l1sx01_hw_init(struct udevice *dev) +{ + struct sharp_lq079l1sx01_priv *priv = dev_get_priv(dev); + int ret; + + if (!priv->panel_sec) + return 0; + + ret = regulator_set_enable_if_allowed(priv->vddio, 1); + if (ret) { + log_debug("%s: enabling vddio-supply failed (%d)\n", + __func__, ret); + return ret; + } + + ret = regulator_set_enable_if_allowed(priv->avdd, 1); + if (ret) { + log_debug("%s: enabling avdd-supply failed (%d)\n", + __func__, ret); + return ret; + } + + mdelay(12); + + ret = regulator_set_enable_if_allowed(priv->vsp, 1); + if (ret) { + log_debug("%s: enabling vsp-supply failed (%d)\n", + __func__, ret); + return ret; + } + + mdelay(12); + + ret = regulator_set_enable_if_allowed(priv->vsn, 1); + if (ret) { + log_debug("%s: enabling vsn-supply failed (%d)\n", + __func__, ret); + return ret; + } + + mdelay(24); + + ret = dm_gpio_set_value(&priv->reset_gpio, 0); + if (ret) { + log_debug("%s: error disabling reset-gpios (%d)\n", + __func__, ret); + return ret; + } + udelay(3); + + ret = dm_gpio_set_value(&priv->reset_gpio, 1); + if (ret) { + log_debug("%s: error enabling reset-gpios (%d)\n", + __func__, ret); + return ret; + } + udelay(3); + + ret = dm_gpio_set_value(&priv->reset_gpio, 0); + if (ret) { + log_debug("%s: error disabling reset-gpios (%d)\n", + __func__, ret); + return ret; + } + mdelay(32); + + return 0; +} + +static int sharp_lq079l1sx01_probe(struct udevice *dev) +{ + struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); + + /* fill characteristics of DSI data link */ + plat->lanes = 4; + plat->format = MIPI_DSI_FMT_RGB888; + plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM; + + return sharp_lq079l1sx01_hw_init(dev); +} + +static const struct panel_ops sharp_lq079l1sx01_ops = { + .enable_backlight = sharp_lq079l1sx01_enable_backlight, + .set_backlight = sharp_lq079l1sx01_set_backlight, + .get_display_timing = sharp_lq079l1sx01_timings, +}; + +static const struct udevice_id sharp_lq079l1sx01_ids[] = { + { .compatible = "sharp,lq079l1sx01" }, + { } +}; + +U_BOOT_DRIVER(sharp_lq079l1sx01) = { + .name = "sharp_lq079l1sx01", + .id = UCLASS_PANEL, + .of_match = sharp_lq079l1sx01_ids, + .ops = &sharp_lq079l1sx01_ops, + .of_to_plat = sharp_lq079l1sx01_of_to_plat, + .probe = sharp_lq079l1sx01_probe, + .plat_auto = sizeof(struct mipi_dsi_panel_plat), + .priv_auto = sizeof(struct sharp_lq079l1sx01_priv), +}; diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra20/tegra-dc.c index d24aa375b39..16a2b5281bf 100644 --- a/drivers/video/tegra20/tegra-dc.c +++ b/drivers/video/tegra20/tegra-dc.c @@ -5,24 +5,16 @@ #include <backlight.h> #include <cpu_func.h> +#include <clk.h> #include <dm.h> #include <fdtdec.h> #include <log.h> #include <panel.h> -#include <part.h> -#include <pwm.h> #include <video.h> -#include <asm/cache.h> -#include <asm/global_data.h> #include <asm/system.h> -#include <asm/gpio.h> #include <asm/io.h> - #include <asm/arch/clock.h> -#include <asm/arch/funcmux.h> -#include <asm/arch/pinmux.h> #include <asm/arch/powergate.h> -#include <asm/arch/pwm.h> #include "tegra-dc.h" @@ -44,7 +36,8 @@ struct tegra_lcd_priv { const struct tegra_dc_soc_info *soc; fdt_addr_t frame_buffer; /* Address of frame buffer */ unsigned pixel_clock; /* Pixel clock in Hz */ - int dc_clk[2]; /* Contains clk and its parent */ + struct clk *clk; + struct clk *clk_parent; ulong scdiv; /* Clock divider used by disp_clk_ctrl */ bool rotation; /* 180 degree panel turn */ int pipe; /* DC controller: 0 for A, 1 for B */ @@ -144,10 +137,9 @@ static int update_display_mode(struct tegra_lcd_priv *priv) val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT; val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT; writel(val, &disp->disp_interface_ctrl); - } - if (priv->soc->has_rgb) writel(0x00010001, &disp->shift_clk_opt); + } val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT; val |= priv->scdiv << SHIFT_CLK_DIVIDER_SHIFT; @@ -267,7 +259,9 @@ static int setup_window(struct tegra_lcd_priv *priv, win->out_h = priv->height; win->phys_addr = priv->frame_buffer; win->stride = priv->width * (1 << priv->log2_bpp) / 8; - debug("%s: depth = %d\n", __func__, priv->log2_bpp); + + log_debug("%s: depth = %d\n", __func__, priv->log2_bpp); + switch (priv->log2_bpp) { case VIDEO_BPP32: win->fmt = COLOR_DEPTH_R8G8B8A8; @@ -279,7 +273,7 @@ static int setup_window(struct tegra_lcd_priv *priv, break; default: - debug("Unsupported LCD bit depth"); + log_debug("Unsupported LCD bit depth\n"); return -1; } @@ -301,7 +295,8 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, void *default_lcd_base) { struct disp_ctl_win window; - unsigned long rate = clock_get_rate(priv->dc_clk[1]); + unsigned long rate = clk_get_rate(priv->clk_parent); + int ret; priv->frame_buffer = (u32)default_lcd_base; @@ -309,14 +304,9 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, * We halve the rate if DISP1 parent is PLLD, since actual parent * is plld_out0 which is PLLD divided by 2. */ - if (priv->dc_clk[1] == CLOCK_ID_DISPLAY) - rate /= 2; - -#ifndef CONFIG_TEGRA20 - /* PLLD2 obeys same rules as PLLD but it is present only on T30+ */ - if (priv->dc_clk[1] == CLOCK_ID_DISPLAY2) + if (priv->clk_parent->id == CLOCK_ID_DISPLAY || + priv->clk_parent->id == CLOCK_ID_DISPLAY2) rate /= 2; -#endif /* * The pixel clock divider is in 7.1 format (where the bottom bit @@ -327,14 +317,14 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, if (!priv->scdiv) priv->scdiv = ((rate * 2 + priv->pixel_clock / 2) / priv->pixel_clock) - 2; - debug("Display clock %lu, divider %lu\n", rate, priv->scdiv); + log_debug("Display clock %lu, divider %lu\n", rate, priv->scdiv); /* * HOST1X is init by default at 150MHz with PLLC as parent */ clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_CGENERAL, 150 * 1000000); - clock_start_periph_pll(priv->dc_clk[0], priv->dc_clk[1], + clock_start_periph_pll(priv->clk->id, priv->clk_parent->id, rate); basic_init(&priv->dc->cmd); @@ -348,8 +338,9 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, if (priv->pixel_clock) update_display_mode(priv); - if (setup_window(priv, &window)) - return -1; + ret = setup_window(priv, &window); + if (ret) + return ret; update_window(priv, &window); @@ -364,10 +355,6 @@ static int tegra_lcd_probe(struct udevice *dev) int ret; /* Initialize the Tegra display controller */ -#ifdef CONFIG_TEGRA20 - funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT); -#endif - if (priv->soc->has_pgate) { uint powergate; @@ -378,14 +365,14 @@ static int tegra_lcd_probe(struct udevice *dev) ret = tegra_powergate_power_off(powergate); if (ret < 0) { - log_err("failed to power off DISP gate: %d", ret); + log_debug("failed to power off DISP gate: %d", ret); return ret; } ret = tegra_powergate_sequence_power_up(powergate, - priv->dc_clk[0]); + priv->clk->id); if (ret < 0) { - log_err("failed to power up DISP gate: %d", ret); + log_debug("failed to power up DISP gate: %d", ret); return ret; } } @@ -402,19 +389,15 @@ static int tegra_lcd_probe(struct udevice *dev) memset((u8 *)plat->base, 0, plat->size); flush_dcache_all(); - if (tegra_display_probe(priv, (void *)plat->base)) { - debug("%s: Failed to probe display driver\n", __func__); - return -1; + ret = tegra_display_probe(priv, (void *)plat->base); + if (ret) { + log_debug("%s: Failed to probe display driver\n", __func__); + return ret; } -#ifdef CONFIG_TEGRA20 - pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_PWM); - pinmux_tristate_disable(PMUX_PINGRP_GPU); -#endif - ret = panel_enable_backlight(priv->panel); if (ret) { - debug("%s: Cannot enable backlight, ret=%d\n", __func__, ret); + log_debug("%s: Cannot enable backlight, ret=%d\n", __func__, ret); return ret; } @@ -427,8 +410,8 @@ static int tegra_lcd_probe(struct udevice *dev) uc_priv->xsize = priv->width; uc_priv->ysize = priv->height; uc_priv->bpix = priv->log2_bpp; - debug("LCD frame buffer at %08x, size %x\n", priv->frame_buffer, - plat->size); + log_debug("LCD frame buffer at %08x, size %x\n", priv->frame_buffer, + plat->size); return panel_set_backlight(priv->panel, BACKLIGHT_DEFAULT); } @@ -445,17 +428,24 @@ static int tegra_lcd_of_to_plat(struct udevice *dev) priv->dc = (struct dc_ctlr *)dev_read_addr_ptr(dev); if (!priv->dc) { - debug("%s: No display controller address\n", __func__); + log_debug("%s: No display controller address\n", __func__); return -EINVAL; } priv->soc = (struct tegra_dc_soc_info *)dev_get_driver_data(dev); - ret = clock_decode_pair(dev, priv->dc_clk); - if (ret < 0) { - debug("%s: Cannot decode clocks for '%s' (ret = %d)\n", - __func__, dev->name, ret); - return -EINVAL; + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get DC clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + priv->clk_parent = devm_clk_get(dev, "parent"); + if (IS_ERR(priv->clk_parent)) { + log_debug("%s: Could not get DC clock parent: %ld\n", + __func__, PTR_ERR(priv->clk_parent)); + return PTR_ERR(priv->clk_parent); } priv->rotation = dev_read_bool(dev, "nvidia,180-rotation"); @@ -463,8 +453,8 @@ static int tegra_lcd_of_to_plat(struct udevice *dev) rgb = fdt_subnode_offset(blob, node, "rgb"); if (rgb < 0) { - debug("%s: Cannot find rgb subnode for '%s' (ret=%d)\n", - __func__, dev->name, rgb); + log_debug("%s: Cannot find rgb subnode for '%s' (ret=%d)\n", + __func__, dev->name, rgb); return -EINVAL; } @@ -474,15 +464,15 @@ static int tegra_lcd_of_to_plat(struct udevice *dev) */ panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel"); if (panel_node < 0) { - debug("%s: Cannot find panel information\n", __func__); + log_debug("%s: Cannot find panel information\n", __func__); return -EINVAL; } ret = uclass_get_device_by_of_offset(UCLASS_PANEL, panel_node, &priv->panel); if (ret) { - debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__, - dev->name, ret); + log_debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__, + dev->name, ret); return ret; } @@ -500,8 +490,8 @@ static int tegra_lcd_of_to_plat(struct udevice *dev) if (ret) { ret = fdtdec_decode_display_timing(blob, rgb, 0, &priv->timing); if (ret) { - debug("%s: Cannot read display timing for '%s' (ret=%d)\n", - __func__, dev->name, ret); + log_debug("%s: Cannot read display timing for '%s' (ret=%d)\n", + __func__, dev->name, ret); return -EINVAL; } } @@ -564,6 +554,9 @@ static const struct udevice_id tegra_lcd_ids[] = { .compatible = "nvidia,tegra114-dc", .data = (ulong)&tegra114_dc_soc_info }, { + .compatible = "nvidia,tegra124-dc", + .data = (ulong)&tegra114_dc_soc_info + }, { /* sentinel */ } }; diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index 6327266dd22..9f39ac7589b 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -5,6 +5,7 @@ */ #include <dm.h> +#include <clk.h> #include <log.h> #include <misc.h> #include <mipi_display.h> @@ -46,10 +47,13 @@ struct tegra_dsi_priv { enum tegra_dsi_format format; - int dsi_clk; + struct clk *clk; + struct clk *clk_parent; + int video_fifo_depth; int host_fifo_depth; + u32 calibration_pads; u32 version; /* for ganged-mode support */ @@ -515,8 +519,9 @@ static void tegra_dsi_pad_calibrate(struct dsi_pad_ctrl_reg *pad) writel(value, TEGRA_VI_BASE + (CSI_CIL_PAD_CONFIG << 2)); } -static void tegra_dsi_mipi_calibrate(struct tegra_dsi_priv *priv) +static void tegra_dsi_mipi_calibrate(struct udevice *dev) { + struct tegra_dsi_priv *priv = dev_get_priv(dev); struct dsi_pad_ctrl_reg *pad = &priv->dsi->pad; u32 value; int ret; @@ -545,15 +550,20 @@ static void tegra_dsi_mipi_calibrate(struct tegra_dsi_priv *priv) DSI_PAD_PREEMP_PD(0x03) | DSI_PAD_PREEMP_PU(0x3); writel(value, &pad->pad_ctrl_3); - ret = misc_write(priv->mipi, 0, NULL, 0); + ret = misc_write(priv->mipi, priv->calibration_pads, NULL, 0); if (ret) log_debug("%s: MIPI calibration failed %d\n", __func__, ret); + + if (priv->slave) + tegra_dsi_mipi_calibrate(priv->slave); } -static void tegra_dsi_set_timeout(struct dsi_timeout_reg *rtimeout, +static void tegra_dsi_set_timeout(struct udevice *dev, unsigned long bclk, unsigned int vrefresh) { + struct tegra_dsi_priv *priv = dev_get_priv(dev); + struct dsi_timeout_reg *rtimeout = &priv->dsi->timeout; unsigned int timeout; u32 value; @@ -569,12 +579,17 @@ static void tegra_dsi_set_timeout(struct dsi_timeout_reg *rtimeout, value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0); writel(value, &rtimeout->dsi_to_tally); + + if (priv->slave) + tegra_dsi_set_timeout(priv->slave, bclk, vrefresh); } -static void tegra_dsi_set_phy_timing(struct dsi_timing_reg *ptiming, +static void tegra_dsi_set_phy_timing(struct udevice *dev, unsigned long period, const struct mipi_dphy_timing *dphy_timing) { + struct tegra_dsi_priv *priv = dev_get_priv(dev); + struct dsi_timing_reg *ptiming = &priv->dsi->ptiming; u32 value; value = DSI_TIMING_FIELD(dphy_timing->hsexit, period, 1) << 24 | @@ -598,6 +613,31 @@ static void tegra_dsi_set_phy_timing(struct dsi_timing_reg *ptiming, DSI_TIMING_FIELD(dphy_timing->tasure, period, 1) << 8 | DSI_TIMING_FIELD(dphy_timing->tago, period, 1); writel(value, &ptiming->dsi_bta_timing); + + if (priv->slave) + tegra_dsi_set_phy_timing(priv->slave, period, dphy_timing); +} + +static u32 tegra_dsi_get_lanes(struct udevice *dev) +{ + struct tegra_dsi_priv *priv = dev_get_priv(dev); + struct mipi_dsi_device *device = &priv->device; + + if (priv->master) { + struct tegra_dsi_priv *mpriv = dev_get_priv(priv->master); + struct mipi_dsi_device *mdevice = &mpriv->device; + + return mdevice->lanes + device->lanes; + } + + if (priv->slave) { + struct tegra_dsi_priv *spriv = dev_get_priv(priv->slave); + struct mipi_dsi_device *sdevice = &spriv->device; + + return device->lanes + sdevice->lanes; + } + + return device->lanes; } static void tegra_dsi_ganged_enable(struct udevice *dev, unsigned int start, @@ -611,7 +651,7 @@ static void tegra_dsi_ganged_enable(struct udevice *dev, unsigned int start, writel(DSI_GANGED_MODE_CONTROL_ENABLE, &ganged->ganged_mode_ctrl); } -static void tegra_dsi_configure(struct udevice *dev, +static void tegra_dsi_configure(struct udevice *dev, unsigned int pipe, unsigned long mode_flags) { struct tegra_dsi_priv *priv = dev_get_priv(dev); @@ -642,7 +682,7 @@ static void tegra_dsi_configure(struct udevice *dev, value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(priv->format) | DSI_CONTROL_LANES(device->lanes - 1) | - DSI_CONTROL_SOURCE(0); + DSI_CONTROL_SOURCE(pipe); writel(value, &misc->dsi_ctrl); writel(priv->video_fifo_depth, &misc->dsi_max_threshold); @@ -680,12 +720,19 @@ static void tegra_dsi_configure(struct udevice *dev, /* horizontal back porch */ hbp = timing->hback_porch.typ * mul / div; - if ((mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0) - hbp += hsw; - /* horizontal front porch */ hfp = timing->hfront_porch.typ * mul / div; + if (priv->master || priv->slave) { + hact /= 2; + hsw /= 2; + hbp = hbp / 2 - 1; + hfp /= 2; + } + + if ((mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0) + hbp += hsw; + /* subtract packet overhead */ hsw -= 10; hbp -= 14; @@ -695,9 +742,6 @@ static void tegra_dsi_configure(struct udevice *dev, writel(hact << 16 | hbp, &len->dsi_pkt_len_2_3); writel(hfp, &len->dsi_pkt_len_4_5); writel(0x0f0f << 16, &len->dsi_pkt_len_6_7); - - /* set SOL delay (for non-burst mode only) */ - writel(8 * mul / div, &misc->dsi_sol_delay); } else { if (priv->master || priv->slave) { /* @@ -717,32 +761,33 @@ static void tegra_dsi_configure(struct udevice *dev, value = MIPI_DCS_WRITE_MEMORY_START << 8 | MIPI_DCS_WRITE_MEMORY_CONTINUE; writel(value, &len->dsi_dcs_cmds); + } - /* set SOL delay */ - if (priv->master || priv->slave) { - unsigned long delay, bclk, bclk_ganged; - unsigned int lanes = device->lanes; - unsigned long htotal = timing->hactive.typ + timing->hfront_porch.typ + - timing->hback_porch.typ + timing->hsync_len.typ; - - /* SOL to valid, valid to FIFO and FIFO write delay */ - delay = 4 + 4 + 2; - delay = DIV_ROUND_UP(delay * mul, div * lanes); - /* FIFO read delay */ - delay = delay + 6; - - bclk = DIV_ROUND_UP(htotal * mul, div * lanes); - bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes); - value = bclk - bclk_ganged + delay + 20; - } else { - /* TODO: revisit for non-ganged mode */ - value = 8 * mul / div; - } - - writel(value, &misc->dsi_sol_delay); + /* set SOL delay */ + if (priv->master || priv->slave) { + unsigned long delay, bclk, bclk_ganged; + unsigned int lanes = tegra_dsi_get_lanes(dev); + unsigned long htotal = timing->hactive.typ + timing->hfront_porch.typ + + timing->hback_porch.typ + timing->hsync_len.typ; + + /* SOL to valid, valid to FIFO and FIFO write delay */ + delay = 4 + 4 + 2; + delay = DIV_ROUND_UP(delay * mul, div * lanes); + /* FIFO read delay */ + delay = delay + 6; + + bclk = DIV_ROUND_UP(htotal * mul, div * lanes); + bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes); + value = bclk - bclk_ganged + delay + 20; + } else { + /* set SOL delay (for non-burst mode only) */ + value = 8 * mul / div; } + writel(value, &misc->dsi_sol_delay); + if (priv->slave) { + tegra_dsi_configure(priv->slave, pipe, mode_flags); /* * TODO: Support modes other than symmetrical left-right * split. @@ -753,15 +798,31 @@ static void tegra_dsi_configure(struct udevice *dev, } } +static void tegra_dsi_enable(struct udevice *dev) +{ + struct tegra_dsi_priv *priv = dev_get_priv(dev); + struct dsi_misc_reg *misc = &priv->dsi->misc; + u32 value; + + /* enable DSI controller */ + value = readl(&misc->dsi_pwr_ctrl); + value |= DSI_POWER_CONTROL_ENABLE; + writel(value, &misc->dsi_pwr_ctrl); + + if (priv->slave) + tegra_dsi_enable(priv->slave); +} + static int tegra_dsi_encoder_enable(struct udevice *dev) { struct tegra_dsi_priv *priv = dev_get_priv(dev); + struct tegra_dc_plat *dc_plat = dev_get_plat(dev); struct mipi_dsi_device *device = &priv->device; struct display_timing *timing = &priv->timing; struct dsi_misc_reg *misc = &priv->dsi->misc; unsigned int mul, div; unsigned long bclk, plld, period; - u32 value; + u32 value, lanes; int ret; /* If for some reasone DSI is enabled then it needs to @@ -780,16 +841,17 @@ static int tegra_dsi_encoder_enable(struct udevice *dev) writel(0, &misc->int_enable); if (priv->version) - tegra_dsi_mipi_calibrate(priv); + tegra_dsi_mipi_calibrate(dev); else tegra_dsi_pad_calibrate(&priv->dsi->pad); tegra_dsi_get_muldiv(device->format, &mul, &div); /* compute byte clock */ - bclk = (timing->pixelclock.typ * mul) / (div * device->lanes); + lanes = tegra_dsi_get_lanes(dev); + bclk = (timing->pixelclock.typ * mul) / (div * lanes); - tegra_dsi_set_timeout(&priv->dsi->timeout, bclk, 60); + tegra_dsi_set_timeout(dev, bclk, 60); /* * Compute bit clock and round up to the next MHz. @@ -813,25 +875,18 @@ static int tegra_dsi_encoder_enable(struct udevice *dev) * The D-PHY timing fields are expressed in byte-clock cycles, so * multiply the period by 8. */ - tegra_dsi_set_phy_timing(&priv->dsi->ptiming, - period * 8, &priv->dphy_timing); + tegra_dsi_set_phy_timing(dev, period * 8, &priv->dphy_timing); /* Perform panel HW setup */ ret = panel_enable_backlight(priv->panel); if (ret) return ret; - tegra_dsi_configure(dev, device->mode_flags); + tegra_dsi_configure(dev, dc_plat->pipe, device->mode_flags); tegra_dc_enable_controller(dev); - /* enable DSI controller */ - value = readl(&misc->dsi_pwr_ctrl); - value |= DSI_POWER_CONTROL_ENABLE; - writel(value, &misc->dsi_pwr_ctrl); - - if (priv->slave) - tegra_dsi_encoder_enable(priv->slave); + tegra_dsi_enable(dev); return 0; } @@ -859,21 +914,35 @@ static void tegra_dsi_init_clocks(struct udevice *dev) struct tegra_dsi_priv *priv = dev_get_priv(dev); struct tegra_dc_plat *dc_plat = dev_get_plat(dev); struct mipi_dsi_device *device = &priv->device; - unsigned int mul, div; + unsigned int mul, div, lanes; unsigned long bclk, plld; - if (!priv->slave) { + /* Switch parents of DSI clocks in case of not standard parent */ + if (priv->clk->id == PERIPH_ID_DSI && + priv->clk_parent->id == CLOCK_ID_DISPLAY2) { + /* Change DSIA clock parent to PLLD2 */ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + + /* DSIA_CLK_SRC */ + setbits_le32(&clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_base, + BIT(25)); + } + + if (priv->clk->id == PERIPH_ID_DSIB && + priv->clk_parent->id == CLOCK_ID_DISPLAY) { /* Change DSIB clock parent to match DSIA */ struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; - clrbits_le32(&clkrst->plld2.pll_base, BIT(25)); /* DSIB_CLK_SRC */ + /* DSIB_CLK_SRC */ + clrbits_le32(&clkrst->plld2.pll_base, BIT(25)); } tegra_dsi_get_muldiv(device->format, &mul, &div); - bclk = (priv->timing.pixelclock.typ * mul) / - (div * device->lanes); + lanes = tegra_dsi_get_lanes(dev); + bclk = (priv->timing.pixelclock.typ * mul) / (div * lanes); plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC); @@ -893,16 +962,16 @@ static void tegra_dsi_init_clocks(struct udevice *dev) 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, plld, 12, 0, 8); + clock_set_rate(priv->clk_parent->id, plld, 12, 0, 8); break; case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ - clock_set_rate(CLOCK_ID_DISPLAY, plld, 26, 0, 8); + clock_set_rate(priv->clk_parent->id, plld, 26, 0, 8); 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, plld, 13, 0, 8); + clock_set_rate(priv->clk_parent->id, plld, 13, 0, 8); break; case CLOCK_OSC_FREQ_19_2: @@ -914,11 +983,7 @@ static void tegra_dsi_init_clocks(struct udevice *dev) break; } - priv->dsi_clk = clock_decode_periph_id(dev); - - clock_enable(priv->dsi_clk); - udelay(2); - reset_set_enable(priv->dsi_clk, 0); + clk_enable(priv->clk); } static int tegra_dsi_ganged_probe(struct udevice *dev) @@ -955,6 +1020,20 @@ static int tegra_dsi_bridge_probe(struct udevice *dev) return -EINVAL; } + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get DSI clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + priv->clk_parent = devm_clk_get(dev, "parent"); + if (IS_ERR(priv->clk_parent)) { + log_debug("%s: Could not get DSI clock parent: %ld\n", + __func__, PTR_ERR(priv->clk_parent)); + return PTR_ERR(priv->clk_parent); + } + priv->video_fifo_depth = 1920; priv->host_fifo_depth = 64; @@ -973,10 +1052,22 @@ static int tegra_dsi_bridge_probe(struct udevice *dev) debug("%s: Cannot get avdd-dsi-csi-supply: error %d\n", __func__, ret); - ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, - "panel", &priv->panel); + /* Check all DSI children */ + device_foreach_child(priv->panel, dev) { + if (device_get_uclass_id(priv->panel) == UCLASS_PANEL) + break; + } + + /* if loop exits without panel device return error */ + if (device_get_uclass_id(priv->panel) != UCLASS_PANEL) { + log_debug("%s: panel not found, ret %d\n", __func__, ret); + return -EINVAL; + } + + ret = uclass_get_device_by_ofnode(UCLASS_PANEL, dev_ofnode(priv->panel), + &priv->panel); if (ret) { - printf("%s: Cannot get panel: error %d\n", __func__, ret); + log_debug("%s: Cannot get panel: error %d\n", __func__, ret); return log_ret(ret); } @@ -988,6 +1079,14 @@ static int tegra_dsi_bridge_probe(struct udevice *dev) log_debug("%s: cannot get MIPI: error %d\n", __func__, ret); return ret; } + + ret = dev_read_u32_index(dev, "nvidia,mipi-calibrate", 1, + &priv->calibration_pads); + if (ret) { + log_debug("%s: cannot get calibration pads: error %d\n", + __func__, ret); + return ret; + } } panel_get_display_timing(priv->panel, &priv->timing); @@ -1028,6 +1127,7 @@ static const struct panel_ops tegra_dsi_bridge_ops = { static const struct udevice_id tegra_dsi_bridge_ids[] = { { .compatible = "nvidia,tegra30-dsi", .data = DSI_V0 }, { .compatible = "nvidia,tegra114-dsi", .data = DSI_V1 }, + { .compatible = "nvidia,tegra124-dsi", .data = DSI_V1 }, { } }; @@ -1036,6 +1136,7 @@ U_BOOT_DRIVER(tegra_dsi) = { .id = UCLASS_PANEL, .of_match = tegra_dsi_bridge_ids, .ops = &tegra_dsi_bridge_ops, + .bind = dm_scan_fdt_dev, .probe = tegra_dsi_bridge_probe, .plat_auto = sizeof(struct tegra_dc_plat), .priv_auto = sizeof(struct tegra_dsi_priv), diff --git a/drivers/video/tegra20/tegra-mipi.c b/drivers/video/tegra20/tegra-mipi.c index 2df3c1a9942..a4f4343d008 100644 --- a/drivers/video/tegra20/tegra-mipi.c +++ b/drivers/video/tegra20/tegra-mipi.c @@ -10,9 +10,10 @@ #include <linux/delay.h> #include <linux/iopoll.h> +#include <asm/arch/clock.h> #include <asm/io.h> -/* MIPI control registers 0x00 ~ 0x60 */ +/* MIPI control registers 0x00 ~ 0x74 */ struct mipi_ctlr { uint mipi_cal_ctrl; uint mipi_cal_autocal_ctrl; @@ -38,8 +39,17 @@ struct mipi_ctlr { uint mipi_cal_bias_pad_cfg0; uint mipi_cal_bias_pad_cfg1; uint mipi_cal_bias_pad_cfg2; + + uint mipi_cal_dsia_config_2; + uint mipi_cal_dsib_config_2; + uint mipi_cal_cilc_config_2; + uint mipi_cal_cild_config_2; + uint mipi_cal_csie_config_2; }; +#define MIPI_DSIA_PADS 0x60 +#define MIPI_DSIB_PADS 0x180 + #define MIPI_CAL_CTRL_NOISE_FILTER(x) (((x) & 0xf) << 26) #define MIPI_CAL_CTRL_PRESCALE(x) (((x) & 0x3) << 24) #define MIPI_CAL_CTRL_CLKEN_OVR BIT(4) @@ -64,26 +74,25 @@ struct mipi_ctlr { #define MIPI_CAL_BIAS_PAD_VAUXP(x) (((x) & 0x7) << 4) #define MIPI_CAL_BIAS_PAD_PDVREG BIT(1) +#define MIPI_CAL_HSCLKPDOSDSI(x) (((x) & 0x1f) << 8) +#define MIPI_CAL_HSCLKPUOSDSI(x) (((x) & 0x1f) << 0) + struct tegra_mipi_priv { struct mipi_ctlr *mipi; struct clk *mipi_cal; + u32 version; }; -static int tegra_mipi_calibrate(struct udevice *dev, int offset, const void *buf, - int size) +enum { + T114, + T124, +}; + +static void tegra114_mipi_pads_cal(struct tegra_mipi_priv *priv, + int calibration_pads) { - struct tegra_mipi_priv *priv = dev_get_priv(dev); u32 value; - value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(0x2) | - MIPI_CAL_BIAS_PAD_DRV_UP_REF(0x0); - writel(value, &priv->mipi->mipi_cal_bias_pad_cfg1); - - value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2); - value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7); - value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7); - writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2); - value = MIPI_CAL_OVERIDE(0x0) | MIPI_CAL_SEL(0x1) | MIPI_CAL_HSPDOS(0x0) | MIPI_CAL_HSPUOS(0x4) | MIPI_CAL_TERMOS(0x5); @@ -99,6 +108,95 @@ static int tegra_mipi_calibrate(struct udevice *dev, int offset, const void *buf value = readl(&priv->mipi->mipi_cal_config_dsid); value &= ~(MIPI_CAL_SEL(0x1)); writel(value, &priv->mipi->mipi_cal_config_dsid); +} + +static void tegra124_mipi_pads_cal(struct tegra_mipi_priv *priv, + int calibration_pads) +{ + u32 value; + + /* Calibrate DSI-A */ + if (calibration_pads == MIPI_DSIA_PADS) { + printf("Calibrating DSI-A pads\n"); + + value = MIPI_CAL_OVERIDE(0x0) | MIPI_CAL_SEL(0x1) | + MIPI_CAL_HSPDOS(0x0) | MIPI_CAL_HSPUOS(0x0) | + MIPI_CAL_TERMOS(0x0); + writel(value, &priv->mipi->mipi_cal_config_dsia); + writel(value, &priv->mipi->mipi_cal_config_dsib); + + value = MIPI_CAL_SEL(0x1) | + MIPI_CAL_HSCLKPDOSDSI(0x1) | + MIPI_CAL_HSCLKPUOSDSI(0x2); + writel(value, &priv->mipi->mipi_cal_dsia_config_2); + writel(value, &priv->mipi->mipi_cal_dsib_config_2); + + /* Deselect PAD C */ + value = readl(&priv->mipi->mipi_cal_cilc_config_2); + value &= ~(MIPI_CAL_SEL(0x1)); + writel(value, &priv->mipi->mipi_cal_cilc_config_2); + + /* Deselect PAD D */ + value = readl(&priv->mipi->mipi_cal_cild_config_2); + value &= ~(MIPI_CAL_SEL(0x1)); + writel(value, &priv->mipi->mipi_cal_cild_config_2); + } + + /* Calibrate DSI-B */ + if (calibration_pads == MIPI_DSIB_PADS) { + printf("Calibrating DSI-B pads\n"); + + value = MIPI_CAL_OVERIDE(0x0) | MIPI_CAL_SEL(0x1) | + MIPI_CAL_HSPDOS(0x0) | MIPI_CAL_HSPUOS(0x0) | + MIPI_CAL_TERMOS(0x0); + writel(value, &priv->mipi->mipi_cal_config_csic); + writel(value, &priv->mipi->mipi_cal_config_csid); + + value = MIPI_CAL_SEL(0x1) | + MIPI_CAL_HSCLKPDOSDSI(0x1) | + MIPI_CAL_HSCLKPUOSDSI(0x2); + writel(value, &priv->mipi->mipi_cal_cilc_config_2); + writel(value, &priv->mipi->mipi_cal_cild_config_2); + + /* Deselect PAD A */ + value = readl(&priv->mipi->mipi_cal_dsia_config_2); + value &= ~(MIPI_CAL_SEL(0x1)); + writel(value, &priv->mipi->mipi_cal_dsia_config_2); + + /* Deselect PAD B */ + value = readl(&priv->mipi->mipi_cal_dsib_config_2); + value &= ~(MIPI_CAL_SEL(0x1)); + writel(value, &priv->mipi->mipi_cal_dsib_config_2); + } +} + +static int tegra_mipi_calibrate(struct udevice *dev, int offset, const void *buf, + int size) +{ + struct tegra_mipi_priv *priv = dev_get_priv(dev); + u32 value; + + value = MIPI_CAL_BIAS_PAD_DRV_DN_REF(0x2) | + MIPI_CAL_BIAS_PAD_DRV_UP_REF(0x0); + writel(value, &priv->mipi->mipi_cal_bias_pad_cfg1); + + value = readl(&priv->mipi->mipi_cal_bias_pad_cfg2); + value &= ~MIPI_CAL_BIAS_PAD_VCLAMP(0x7); + value &= ~MIPI_CAL_BIAS_PAD_VAUXP(0x7); + writel(value, &priv->mipi->mipi_cal_bias_pad_cfg2); + + switch (priv->version) { + case T114: + tegra114_mipi_pads_cal(priv, offset); + break; + + case T124: + tegra124_mipi_pads_cal(priv, offset); + break; + + default: + return -EINVAL; + } value = readl(&priv->mipi->mipi_cal_ctrl); value &= ~MIPI_CAL_CTRL_NOISE_FILTER(0xf); @@ -134,6 +232,11 @@ static int tegra_mipi_enable(struct udevice *dev, bool val) struct tegra_mipi_priv *priv = dev_get_priv(dev); u32 value; + reset_set_enable(priv->mipi_cal->id, 1); + mdelay(100); + reset_set_enable(priv->mipi_cal->id, 0); + mdelay(1); + clk_enable(priv->mipi_cal); value = readl(&priv->mipi->mipi_cal_bias_pad_cfg0); @@ -157,6 +260,8 @@ static int tegra_mipi_probe(struct udevice *dev) { struct tegra_mipi_priv *priv = dev_get_priv(dev); + priv->version = dev_get_driver_data(dev); + priv->mipi = (struct mipi_ctlr *)dev_read_addr_ptr(dev); if (!priv->mipi) { log_debug("%s: no MIPI controller address\n", __func__); @@ -174,7 +279,8 @@ static int tegra_mipi_probe(struct udevice *dev) } static const struct udevice_id tegra_mipi_ids[] = { - { .compatible = "nvidia,tegra114-mipi" }, + { .compatible = "nvidia,tegra114-mipi", .data = T114 }, + { .compatible = "nvidia,tegra124-mipi", .data = T124 }, { } }; diff --git a/include/configs/mocha.h b/include/configs/mocha.h new file mode 100644 index 00000000000..1c2eb906085 --- /dev/null +++ b/include/configs/mocha.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. + * + * Copyright (c) 2024, Svyatoslav Ryhel <clamor95@gmail.com> + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include "tegra124-common.h" + +/* High-level configuration options */ +#define CFG_TEGRA_BOARD_STRING "Xiaomi Mocha" + +/* Board-specific serial config */ +#define CFG_SYS_NS16550_COM1 NV_PA_APB_UARTD_BASE + +#ifdef CONFIG_TEGRA_SUPPORT_NON_SECURE + #define CFG_PRAM 0x38400 /* 225 MB */ +#endif + +#include "tegra-common-post.h" + +#endif /* __CONFIG_H */ |