This commit is contained in:
Tom Rini
2025-03-12 07:56:16 -06:00
39 changed files with 2459 additions and 192 deletions
+1
View File
@@ -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 \
+592
View File
@@ -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>;
};
};
+4
View File
@@ -9,5 +9,9 @@
dc@54200000 {
bootph-all;
};
dc@54240000 {
bootph-all;
};
};
};
+11 -12
View File
@@ -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 {
+1 -1
View File
@@ -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
+29 -1
View File
@@ -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,
&divider_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;
}
+5
View File
@@ -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
+1
View File
@@ -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
+91
View File
@@ -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",
""
);
+55
View File
@@ -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_ */
+12
View File
@@ -0,0 +1,12 @@
if TARGET_MOCHA
config SYS_BOARD
default "mocha"
config SYS_VENDOR
default "xiaomi"
config SYS_CONFIG_NAME
default "mocha"
endif
+8
View File
@@ -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
+9
View File
@@ -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
+49
View File
@@ -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);
}
+41
View File
@@ -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
+23
View File
@@ -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
View File
@@ -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;
}
}
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+91
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1
View File
@@ -69,4 +69,5 @@ Board-specific doc
variscite/index
wexler/index
xen/index
xiaomi/index
xilinx/index
+9
View File
@@ -0,0 +1,9 @@
.. SPDX-License-Identifier: GPL-2.0+
Xiaomi
======
.. toctree::
:maxdepth: 2
mocha
+112
View File
@@ -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.
+56
View File
@@ -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" },
{ },
};
+19
View File
@@ -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"
+2
View File
@@ -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
+302
View File
@@ -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),
};
+288
View File
@@ -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),
};
+50 -57
View File
@@ -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 */
}
+167 -66
View File
@@ -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),
+120 -14
View File
@@ -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 },
{ }
};
+25
View File
@@ -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 */