Merge branch 'staging' of https://source.denx.de/u-boot/custodians/u-boot-tegra into next
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
@@ -9,5 +9,9 @@
|
||||
dc@54200000 {
|
||||
bootph-all;
|
||||
};
|
||||
|
||||
dc@54240000 {
|
||||
bootph-all;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
""
|
||||
);
|
||||
@@ -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_ */
|
||||
@@ -0,0 +1,12 @@
|
||||
if TARGET_MOCHA
|
||||
|
||||
config SYS_BOARD
|
||||
default "mocha"
|
||||
|
||||
config SYS_VENDOR
|
||||
default "xiaomi"
|
||||
|
||||
config SYS_CONFIG_NAME
|
||||
default "mocha"
|
||||
|
||||
endif
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
+272
-34
@@ -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;
|
||||
unsigned int x, y, freq;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -69,4 +69,5 @@ Board-specific doc
|
||||
variscite/index
|
||||
wexler/index
|
||||
xen/index
|
||||
xiaomi/index
|
||||
xilinx/index
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
Xiaomi
|
||||
======
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
mocha
|
||||
@@ -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.
|
||||
@@ -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" },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
@@ -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),
|
||||
};
|
||||
@@ -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,15 +304,10 @@ 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)
|
||||
if (priv->clk_parent->id == CLOCK_ID_DISPLAY ||
|
||||
priv->clk_parent->id == CLOCK_ID_DISPLAY2)
|
||||
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)
|
||||
rate /= 2;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The pixel clock divider is in 7.1 format (where the bottom bit
|
||||
* represents 0.5). Here we calculate the divider needed to get from
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -563,6 +553,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 */
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
Reference in New Issue
Block a user