mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-08-05 23:06:59 +02:00
Merge branch 'staging' of https://source.denx.de/u-boot/custodians/u-boot-tegra
- Pegatron Chagall, Samsung Galaxy R (GT-I9103) and Captivate Glide (SGH-i927) support
This commit is contained in:
commit
488ae65f39
@ -92,6 +92,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += \
|
||||
tegra20-motorola-olympus.dtb \
|
||||
tegra20-paz00.dtb \
|
||||
tegra20-plutux.dtb \
|
||||
tegra20-samsung-bose.dtb \
|
||||
tegra20-samsung-n1.dtb \
|
||||
tegra20-seaboard.dtb \
|
||||
tegra20-tec.dtb \
|
||||
tegra20-trimslice.dtb \
|
||||
@ -117,6 +119,7 @@ dtb-$(CONFIG_ARCH_TEGRA) += \
|
||||
tegra30-lg-p895.dtb \
|
||||
tegra30-microsoft-surface-rt.dtb \
|
||||
tegra30-ouya.dtb \
|
||||
tegra30-pegatron-chagall.dtb \
|
||||
tegra30-tec-ng.dtb \
|
||||
tegra30-wexler-qc750.dtb \
|
||||
tegra114-asus-tf701t.dtb \
|
||||
|
@ -40,6 +40,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000014 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -36,6 +36,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000014 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -46,6 +46,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000014 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -62,6 +62,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000014 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
119
arch/arm/dts/tegra20-samsung-bose.dts
Normal file
119
arch/arm/dts/tegra20-samsung-bose.dts
Normal file
@ -0,0 +1,119 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
|
||||
#include "tegra20-samsung-n1-common.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Samsung Captivate Glide (SGH-i927)";
|
||||
compatible = "samsung,bose", "nvidia,tegra20";
|
||||
|
||||
aliases {
|
||||
spi0 = &panel_spi;
|
||||
};
|
||||
|
||||
host1x@50000000 {
|
||||
dc@54200000 {
|
||||
rgb {
|
||||
status = "okay";
|
||||
|
||||
port {
|
||||
dpi_output: endpoint {
|
||||
remote-endpoint = <&panel_input>;
|
||||
bus-width = <24>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pinmux@70000014 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
||||
state_default: pinmux {
|
||||
conf-dtf {
|
||||
nvidia,pins = "dtf", "spdi", "spib", "spih";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_UP>;
|
||||
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||
};
|
||||
|
||||
conf-gpv {
|
||||
nvidia,pins = "gpv";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
|
||||
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||
};
|
||||
|
||||
conf-kbcd {
|
||||
nvidia,pins = "kbcd";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
|
||||
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||
};
|
||||
|
||||
drive-dap {
|
||||
nvidia,pins = "drive_dap2", "drive_dap3";
|
||||
nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>;
|
||||
nvidia,schmitt = <TEGRA_PIN_ENABLE>;
|
||||
nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>;
|
||||
nvidia,pull-down-strength = <31>;
|
||||
nvidia,pull-up-strength = <31>;
|
||||
nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_SLOWEST>;
|
||||
nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_SLOWEST>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
panel_spi: spi@7000d800 {
|
||||
status = "okay";
|
||||
spi-max-frequency = <1000000>;
|
||||
|
||||
panel: panel@2 {
|
||||
/* 480x800 AMOLED panel */
|
||||
compatible = "samsung,bose-panel", "samsung,s6e63m0";
|
||||
reg = <2>;
|
||||
|
||||
spi-max-frequency = <1000000>;
|
||||
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
|
||||
reset-gpios = <&gpio TEGRA_GPIO(C, 1) GPIO_ACTIVE_LOW>;
|
||||
|
||||
vdd3-supply = <&vlcd_1v8_reg>;
|
||||
vci-supply = <&vlcd_3v0_reg>;
|
||||
|
||||
panel-width-mm = <52>;
|
||||
panel-height-mm = <87>;
|
||||
|
||||
port {
|
||||
panel_input: endpoint {
|
||||
remote-endpoint = <&dpi_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sdhci@c8000400 {
|
||||
broken-cd;
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
switch-hall {
|
||||
label = "Keyboard Slide";
|
||||
gpios = <&gpio TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
|
||||
linux,input-type = <EV_SW>;
|
||||
linux,code = <SW_KEYPAD_SLIDE>;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
|
||||
led-kbd {
|
||||
label = "Keyboard backlight";
|
||||
gpios = <&gpio TEGRA_GPIO(L, 5) GPIO_ACTIVE_HIGH>;
|
||||
default-state = "off";
|
||||
};
|
||||
};
|
||||
};
|
428
arch/arm/dts/tegra20-samsung-n1-common.dtsi
Normal file
428
arch/arm/dts/tegra20-samsung-n1-common.dtsi
Normal file
@ -0,0 +1,428 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include "tegra20.dtsi"
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
stdout-path = &uartb;
|
||||
};
|
||||
|
||||
aliases {
|
||||
i2c0 = &pwr_i2c;
|
||||
|
||||
mmc0 = &sdmmc4; /* eMMC */
|
||||
mmc1 = &sdmmc3; /* uSD slot */
|
||||
|
||||
rtc0 = &pmic;
|
||||
rtc1 = "/rtc@7000e000";
|
||||
|
||||
usb0 = µ_usb;
|
||||
};
|
||||
|
||||
memory {
|
||||
device_type = "memory";
|
||||
reg = <0x00000000 0x40000000>; /* 1 GB */
|
||||
};
|
||||
|
||||
pinmux@70000014 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
||||
state_default: pinmux {
|
||||
ata {
|
||||
nvidia,pins = "ata", "atc", "atd", "ate",
|
||||
"gmb", "gmd", "irrx", "irtx",
|
||||
"spid", "spie";
|
||||
nvidia,function = "gmi";
|
||||
};
|
||||
|
||||
atb {
|
||||
nvidia,pins = "atb", "gma", "gme";
|
||||
nvidia,function = "sdio4";
|
||||
};
|
||||
|
||||
cdev1 {
|
||||
nvidia,pins = "cdev1";
|
||||
nvidia,function = "plla_out";
|
||||
};
|
||||
|
||||
cdev2 {
|
||||
nvidia,pins = "cdev2";
|
||||
nvidia,function = "pllp_out4";
|
||||
};
|
||||
|
||||
crtp {
|
||||
nvidia,pins = "crtp";
|
||||
nvidia,function = "crt";
|
||||
};
|
||||
|
||||
csus {
|
||||
nvidia,pins = "csus";
|
||||
nvidia,function = "vi_sensor_clk";
|
||||
};
|
||||
|
||||
dap1 {
|
||||
nvidia,pins = "dap1";
|
||||
nvidia,function = "dap1";
|
||||
};
|
||||
|
||||
dap2 {
|
||||
nvidia,pins = "dap2";
|
||||
nvidia,function = "dap2";
|
||||
};
|
||||
|
||||
dap3 {
|
||||
nvidia,pins = "dap3";
|
||||
nvidia,function = "dap3";
|
||||
};
|
||||
|
||||
dap4 {
|
||||
nvidia,pins = "dap4";
|
||||
nvidia,function = "dap4";
|
||||
};
|
||||
|
||||
ddc {
|
||||
nvidia,pins = "ddc";
|
||||
nvidia,function = "rsvd4";
|
||||
};
|
||||
|
||||
pta {
|
||||
nvidia,pins = "pta";
|
||||
nvidia,function = "i2c2";
|
||||
};
|
||||
|
||||
spif {
|
||||
nvidia,pins = "spif", "uac";
|
||||
nvidia,function = "rsvd4";
|
||||
};
|
||||
|
||||
dta {
|
||||
nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
|
||||
nvidia,function = "vi";
|
||||
};
|
||||
|
||||
dtf {
|
||||
nvidia,pins = "dtf";
|
||||
nvidia,function = "i2c3";
|
||||
};
|
||||
|
||||
gmc {
|
||||
nvidia,pins = "gmc";
|
||||
nvidia,function = "uartd";
|
||||
};
|
||||
|
||||
gpu {
|
||||
nvidia,pins = "gpu", "uaa", "uab";
|
||||
nvidia,function = "uarta";
|
||||
};
|
||||
|
||||
gpu7 {
|
||||
nvidia,pins = "gpu7";
|
||||
nvidia,function = "rtck";
|
||||
};
|
||||
|
||||
gpv {
|
||||
nvidia,pins = "gpv", "slxa", "slxk";
|
||||
nvidia,function = "pcie";
|
||||
};
|
||||
|
||||
hdint {
|
||||
nvidia,pins = "hdint", "spdi", "spdo";
|
||||
nvidia,function = "rsvd2";
|
||||
};
|
||||
|
||||
i2cp {
|
||||
nvidia,pins = "i2cp";
|
||||
nvidia,function = "i2cp";
|
||||
};
|
||||
|
||||
kbca {
|
||||
nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
|
||||
"kbce", "kbcf";
|
||||
nvidia,function = "kbc";
|
||||
};
|
||||
|
||||
lcsn {
|
||||
nvidia,pins = "lcsn", "lsck", "lsda", "lsdi";
|
||||
nvidia,function = "spi3";
|
||||
};
|
||||
|
||||
ld0 {
|
||||
nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
|
||||
"ld5", "ld6", "ld7", "ld8", "ld9",
|
||||
"ld10", "ld11", "ld12", "ld13", "ld14",
|
||||
"ld15", "ld16", "ld17", "ldc", "ldi",
|
||||
"lhp0", "lhp1", "lhp2", "lhs", "lm0",
|
||||
"lm1", "lpp", "lpw0", "lpw1", "lpw2",
|
||||
"lsc0", "lsc1", "lspi", "lvp0", "lvp1",
|
||||
"lvs";
|
||||
nvidia,function = "displaya";
|
||||
};
|
||||
|
||||
owc {
|
||||
nvidia,pins = "owc";
|
||||
nvidia,function = "owr";
|
||||
};
|
||||
|
||||
pmc {
|
||||
nvidia,pins = "pmc";
|
||||
nvidia,function = "pwr_on";
|
||||
};
|
||||
|
||||
rm {
|
||||
nvidia,pins = "rm";
|
||||
nvidia,function = "i2c1";
|
||||
};
|
||||
|
||||
sdb {
|
||||
nvidia,pins = "sdb", "sdc", "sdd";
|
||||
nvidia,function = "sdio3";
|
||||
};
|
||||
|
||||
sdio1 {
|
||||
nvidia,pins = "sdio1";
|
||||
nvidia,function = "sdio1";
|
||||
};
|
||||
|
||||
slxc {
|
||||
nvidia,pins = "slxc", "slxd";
|
||||
nvidia,function = "spi4";
|
||||
};
|
||||
|
||||
spig {
|
||||
nvidia,pins = "spig", "spih";
|
||||
nvidia,function = "spi2_alt";
|
||||
};
|
||||
|
||||
uad {
|
||||
nvidia,pins = "uad";
|
||||
nvidia,function = "irda";
|
||||
};
|
||||
|
||||
uca {
|
||||
nvidia,pins = "uca", "ucb";
|
||||
nvidia,function = "uartc";
|
||||
};
|
||||
|
||||
uda {
|
||||
nvidia,pins = "uda";
|
||||
nvidia,function = "spi1";
|
||||
};
|
||||
|
||||
spia {
|
||||
nvidia,pins = "spia", "spib", "spic";
|
||||
nvidia,function = "spi2";
|
||||
};
|
||||
|
||||
conf-cdev1 {
|
||||
nvidia,pins = "cdev1", "cdev2", "dap1", "dap2",
|
||||
"dap3", "dap4", "ddc", "dte", "gma",
|
||||
"gmc", "gmd", "gme", "gpu7", "hdint",
|
||||
"i2cp", "lcsn", "lhs", "lm0", "lm1",
|
||||
"lpw1", "lsc0", "lsck", "lsda", "lsdi",
|
||||
"lspi", "lvs", "pmc", "pta", "rm",
|
||||
"sdb", "sdio1", "uac", "uda", "ck32",
|
||||
"ddrc", "pmca", "pmcb", "pmcc", "pmcd",
|
||||
"xm2c", "xm2d";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
|
||||
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||
};
|
||||
|
||||
conf-crtp {
|
||||
nvidia,pins = "crtp", "lvp0";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
|
||||
nvidia,tristate = <TEGRA_PIN_ENABLE>;
|
||||
};
|
||||
|
||||
conf-csus {
|
||||
nvidia,pins = "csus", "spid";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
|
||||
nvidia,tristate = <TEGRA_PIN_ENABLE>;
|
||||
};
|
||||
|
||||
conf-ata {
|
||||
nvidia,pins = "ata", "atb", "atc", "ate",
|
||||
"gmb", "gpu", "irrx", "irtx",
|
||||
"kbca", "kbcc", "kbce", "kbcf",
|
||||
"ldc", "lpw0", "lpw2", "lsc1", "sdc",
|
||||
"sdd", "spig", "uaa", "uab",
|
||||
"uad", "uca", "ucb", "pmce";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_UP>;
|
||||
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||
};
|
||||
|
||||
conf-owc {
|
||||
nvidia,pins = "owc";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_UP>;
|
||||
nvidia,tristate = <TEGRA_PIN_ENABLE>;
|
||||
};
|
||||
|
||||
conf-atd {
|
||||
nvidia,pins = "atd", "dta", "dtb", "dtc", "dtd",
|
||||
"kbcb", "ld0", "ld1", "ld10", "ld11",
|
||||
"ld12", "ld13", "ld14", "ld15", "ld16",
|
||||
"ld17", "ld2", "ld3", "ld4", "ld5",
|
||||
"ld6", "ld7", "ld8", "ld9", "ldi",
|
||||
"lhp0", "lhp1", "lhp2", "lpp", "lvp1",
|
||||
"slxa", "slxc", "slxd", "slxk", "spdo",
|
||||
"spia", "spic", "spie", "spif";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
|
||||
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||
};
|
||||
|
||||
drive-ao1 {
|
||||
nvidia,pins = "drive_ao1", "drive_at1", "drive_dbg",
|
||||
"drive_vi1", "drive_vi2";
|
||||
nvidia,high-speed-mode = <TEGRA_PIN_DISABLE>;
|
||||
nvidia,schmitt = <TEGRA_PIN_ENABLE>;
|
||||
nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>;
|
||||
nvidia,pull-down-strength = <31>;
|
||||
nvidia,pull-up-strength = <31>;
|
||||
nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_SLOWEST>;
|
||||
nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_SLOWEST>;
|
||||
};
|
||||
|
||||
drive-sdio1 {
|
||||
nvidia,pins = "drive_sdio1";
|
||||
nvidia,high-speed-mode = <TEGRA_PIN_DISABLE>;
|
||||
nvidia,schmitt = <TEGRA_PIN_ENABLE>;
|
||||
nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>;
|
||||
nvidia,pull-down-strength = <31>;
|
||||
nvidia,pull-up-strength = <31>;
|
||||
nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_SLOWEST>;
|
||||
nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_SLOWEST>;
|
||||
};
|
||||
|
||||
drive-ddc {
|
||||
nvidia,pins = "drive_ddc";
|
||||
nvidia,high-speed-mode = <TEGRA_PIN_DISABLE>;
|
||||
nvidia,schmitt = <TEGRA_PIN_ENABLE>;
|
||||
nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>;
|
||||
nvidia,pull-down-strength = <31>;
|
||||
nvidia,pull-up-strength = <31>;
|
||||
nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>;
|
||||
nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
uartb: serial@70006040 {
|
||||
clocks = <&tegra_car 7>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pwr_i2c: i2c@7000d000 {
|
||||
status = "okay";
|
||||
clock-frequency = <400000>;
|
||||
|
||||
pmic: max8907@3c {
|
||||
compatible = "maxim,max8907";
|
||||
reg = <0x3c>;
|
||||
|
||||
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
|
||||
#gpio-cells = <2>;
|
||||
gpio-controller;
|
||||
|
||||
maxim,system-power-controller;
|
||||
|
||||
regulators {
|
||||
vlcd_1v8_reg: ldo3 {
|
||||
regulator-name = "vlcd_1v8";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
usb_phy_reg: ldo4 {
|
||||
regulator-name = "vap_usb_3v3";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
vlcd_3v0_reg: ldo12 {
|
||||
regulator-name = "vlcd_3v0";
|
||||
regulator-min-microvolt = <3000000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
};
|
||||
|
||||
vmmc_usd_reg: ldo16 {
|
||||
regulator-name = "vmmc_usd";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
micro_usb: usb@c5000000 {
|
||||
status = "okay";
|
||||
dr_mode = "otg";
|
||||
};
|
||||
|
||||
usb-phy@c5000000 {
|
||||
status = "okay";
|
||||
vbus-supply = <&usb_phy_reg>;
|
||||
};
|
||||
|
||||
sdmmc3: sdhci@c8000400 {
|
||||
status = "okay";
|
||||
bus-width = <4>;
|
||||
|
||||
vmmc-supply = <&vmmc_usd_reg>;
|
||||
vqmmc-supply = <&vdd_3v3_sys>;
|
||||
};
|
||||
|
||||
sdmmc4: sdhci@c8000600 {
|
||||
status = "okay";
|
||||
bus-width = <8>;
|
||||
non-removable;
|
||||
|
||||
vmmc-supply = <&vdd_3v3_sys>;
|
||||
vqmmc-supply = <&vdd_3v3_sys>;
|
||||
};
|
||||
|
||||
/* 32KHz oscillator which is used by PMC */
|
||||
clk32k_in: clock-32k-in {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <32768>;
|
||||
clock-output-names = "ref-oscillator";
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
key-power {
|
||||
label = "Power";
|
||||
gpios = <&gpio TEGRA_GPIO(U, 5) GPIO_ACTIVE_HIGH>;
|
||||
linux,code = <KEY_ENTER>;
|
||||
};
|
||||
|
||||
key-volume-up {
|
||||
label = "Volume Up";
|
||||
gpios = <&gpio TEGRA_GPIO(Q, 1) GPIO_ACTIVE_LOW>;
|
||||
linux,code = <KEY_UP>;
|
||||
};
|
||||
|
||||
key-volume-down {
|
||||
label = "Volume Down";
|
||||
gpios = <&gpio TEGRA_GPIO(Q, 2) GPIO_ACTIVE_LOW>;
|
||||
linux,code = <KEY_DOWN>;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_3v3_sys: regulator-3v3 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vdd_3v3_vs";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
};
|
184
arch/arm/dts/tegra20-samsung-n1.dts
Normal file
184
arch/arm/dts/tegra20-samsung-n1.dts
Normal file
@ -0,0 +1,184 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
|
||||
#include "tegra20-samsung-n1-common.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Samsung Galaxy R (GT-I9103)";
|
||||
compatible = "samsung,n1", "nvidia,tegra20";
|
||||
|
||||
aliases {
|
||||
i2c10 = &cmc_i2c;
|
||||
spi0 = &panel_spi;
|
||||
};
|
||||
|
||||
host1x@50000000 {
|
||||
dc@54200000 {
|
||||
rgb {
|
||||
status = "okay";
|
||||
|
||||
port {
|
||||
dpi_output: endpoint {
|
||||
remote-endpoint = <&bridge_input>;
|
||||
bus-width = <24>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pinmux@70000014 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
||||
state_default: pinmux {
|
||||
conf-dtf {
|
||||
nvidia,pins = "dtf", "spdi", "spih";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
|
||||
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||
};
|
||||
|
||||
conf-gpv {
|
||||
nvidia,pins = "gpv", "spib";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
|
||||
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||
};
|
||||
|
||||
conf-kbcd {
|
||||
nvidia,pins = "kbcd";
|
||||
nvidia,pull = <TEGRA_PIN_PULL_UP>;
|
||||
nvidia,tristate = <TEGRA_PIN_DISABLE>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
i2c@7000d000 {
|
||||
max8907@3c {
|
||||
regulators {
|
||||
vcmc623_io_1v8: ldo15 {
|
||||
regulator-name = "vcmc623_io_1v8";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cmc_i2c: i2c-10 {
|
||||
compatible = "i2c-gpio";
|
||||
|
||||
sda-gpios = <&gpio TEGRA_GPIO(Z, 3) GPIO_ACTIVE_HIGH>;
|
||||
scl-gpios = <&gpio TEGRA_GPIO(C, 6) GPIO_ACTIVE_HIGH>;
|
||||
|
||||
i2c-gpio,scl-output-only;
|
||||
i2c-gpio,delay-us = <1>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cmc623: bridge@38 {
|
||||
compatible = "samsung,cmc623";
|
||||
reg = <0x38>;
|
||||
|
||||
enable-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio TEGRA_GPIO(J, 6) GPIO_ACTIVE_HIGH>;
|
||||
|
||||
bypass-gpios = <&gpio TEGRA_GPIO(BB, 5) GPIO_ACTIVE_LOW>;
|
||||
sleep-gpios = <&gpio TEGRA_GPIO(W, 0) GPIO_ACTIVE_HIGH>;
|
||||
|
||||
vdd3v0-supply = <&vcmc623_3v0>;
|
||||
vdd1v2-supply = <&vcmc623_1v2>;
|
||||
vddio1v8-supply = <&vcmc623_io_1v8>;
|
||||
|
||||
cmc623_backlight: backlight {
|
||||
compatible = "samsung,cmc623-backlight";
|
||||
|
||||
enable-gpios = <&gpio TEGRA_GPIO(R, 3) GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
|
||||
bridge_input: endpoint {
|
||||
remote-endpoint = <&dpi_output>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
|
||||
bridge_output: endpoint {
|
||||
remote-endpoint = <&panel_input>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
panel_spi: spi@7000d800 {
|
||||
status = "okay";
|
||||
spi-max-frequency = <1000000>;
|
||||
|
||||
panel: panel@2 {
|
||||
/* 480x800 TFT LCD panel */
|
||||
compatible = "sony,l4f00430t01";
|
||||
reg = <2>;
|
||||
|
||||
spi-max-frequency = <1000000>;
|
||||
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
|
||||
reset-gpios = <&gpio TEGRA_GPIO(C, 1) GPIO_ACTIVE_LOW>;
|
||||
|
||||
vdd1v8-supply = <&vlcd_1v8_reg>;
|
||||
vdd3v0-supply = <&vlcd_3v0_reg>;
|
||||
|
||||
panel-width-mm = <55>;
|
||||
panel-height-mm = <91>;
|
||||
|
||||
backlight = <&cmc623_backlight>;
|
||||
|
||||
port {
|
||||
panel_input: endpoint {
|
||||
remote-endpoint = <&bridge_output>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sdhci@c8000400 {
|
||||
/* battery blocks the sdcard slot and the device lacks CD pin */
|
||||
non-removable;
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
key-home {
|
||||
label = "Home";
|
||||
gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>;
|
||||
linux,code = <KEY_ENTER>;
|
||||
};
|
||||
};
|
||||
|
||||
vcmc623_3v0: regulator-cmc623-3v0 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcmc623_3v0";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
|
||||
vcmc623_1v2: regulator-cmc623-1v2 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vcmc623_1v2";
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
gpio = <&gpio TEGRA_GPIO(L, 5) GPIO_ACTIVE_HIGH>;
|
||||
enable-active-high;
|
||||
};
|
||||
};
|
@ -249,6 +249,35 @@
|
||||
*/
|
||||
};
|
||||
|
||||
/* Audio Bitstream Engine */
|
||||
bsea@60011000 {
|
||||
compatible = "nvidia,tegra20-bsea";
|
||||
reg = <0x60011000 0x1000>, <0x4000c000 0x4000>;
|
||||
reg-names = "bsea", "iram-buffer";
|
||||
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "bsea";
|
||||
clocks = <&tegra_car TEGRA20_CLK_BSEA>;
|
||||
resets = <&tegra_car 62>;
|
||||
reset-names = "bsea";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
/* Video Bitstream Engine */
|
||||
bsev@6001b000 {
|
||||
compatible = "nvidia,tegra20-bsev";
|
||||
reg = <0x6001b000 0x1000>, <0x40008000 0x4000>;
|
||||
reg-names = "bsev", "iram-buffer";
|
||||
interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "bsev";
|
||||
clocks = <&tegra_car TEGRA20_CLK_BSEV>,
|
||||
<&tegra_car TEGRA20_CLK_VDE>;
|
||||
clock-names = "bsev", "vde";
|
||||
resets = <&tegra_car 63>,
|
||||
<&tegra_car 61>;
|
||||
reset-names = "bsev", "vde";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
apbmisc@70000800 {
|
||||
compatible = "nvidia,tegra20-apbmisc";
|
||||
reg = <0x70000800 0x64 /* Chip revision */
|
||||
|
@ -44,6 +44,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000868 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -50,6 +50,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000868 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -53,6 +53,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000868 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -37,6 +37,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000868 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -60,6 +60,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000868 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -43,6 +43,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000868 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -42,6 +42,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000868 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -56,6 +56,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000868 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
1291
arch/arm/dts/tegra30-pegatron-chagall.dts
Normal file
1291
arch/arm/dts/tegra30-pegatron-chagall.dts
Normal file
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
bsev@6001b000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pinmux@70000868 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&state_default>;
|
||||
|
@ -373,6 +373,35 @@
|
||||
*/
|
||||
};
|
||||
|
||||
/* Audio Bitstream Engine */
|
||||
bsea@60011000 {
|
||||
compatible = "nvidia,tegra30-bsea";
|
||||
reg = <0x60011000 0x1000>, <0x4000c000 0x4000>;
|
||||
reg-names = "bsea", "iram-buffer";
|
||||
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "bsea";
|
||||
clocks = <&tegra_car TEGRA30_CLK_BSEA>;
|
||||
resets = <&tegra_car 62>;
|
||||
reset-names = "bsea";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
/* Video Bitstream Engine */
|
||||
bsev@6001b000 {
|
||||
compatible = "nvidia,tegra30-bsev";
|
||||
reg = <0x6001b000 0x1000>, <0x40008000 0x4000>;
|
||||
reg-names = "bsev", "iram-buffer";
|
||||
interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "bsev";
|
||||
clocks = <&tegra_car TEGRA30_CLK_BSEV>,
|
||||
<&tegra_car TEGRA30_CLK_VDE>;
|
||||
clock-names = "bsev", "vde";
|
||||
resets = <&tegra_car 63>,
|
||||
<&tegra_car 61>;
|
||||
reset-names = "bsev", "vde";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
apbmisc@70000800 {
|
||||
compatible = "nvidia,tegra30-apbmisc", "nvidia,tegra20-apbmisc";
|
||||
reg = <0x70000800 0x64 /* Chip revision */
|
||||
|
@ -54,6 +54,13 @@ int tegra_get_chip_sku(void);
|
||||
*/
|
||||
int tegra_get_chip(void);
|
||||
|
||||
/**
|
||||
* Returns the pure SOC major version from the HIDREV register
|
||||
*
|
||||
* Return: SOC major version
|
||||
*/
|
||||
u32 tegra_get_major_version(void);
|
||||
|
||||
/**
|
||||
* Returns the SKU ID from the sku_info register
|
||||
*
|
||||
|
@ -7,41 +7,36 @@
|
||||
#ifndef _CRYPTO_H_
|
||||
#define _CRYPTO_H_
|
||||
|
||||
#define TEGRA_AES_SLOT_SBK 0
|
||||
|
||||
/**
|
||||
* Sign a block of data
|
||||
* sign_data_block - Sign a block of data
|
||||
*
|
||||
* \param source Source data
|
||||
* \param length Size of source data
|
||||
* \param signature Destination address for signature, AES_KEY_LENGTH bytes
|
||||
* @source Source data
|
||||
* @length Size of source data in bytes
|
||||
* @signature Destination address for signature, AES_KEY_LENGTH bytes
|
||||
* Return: 0 on success, negative value on failure
|
||||
*/
|
||||
int sign_data_block(u8 *source, unsigned int length, u8 *signature);
|
||||
|
||||
/**
|
||||
* Sign an encrypted block of data
|
||||
* encrypt_data_block - Encrypt a block of data
|
||||
*
|
||||
* \param source Source data
|
||||
* \param length Size of source data
|
||||
* \param signature Destination address for signature, AES_KEY_LENGTH bytes
|
||||
* \param key AES128 encryption key
|
||||
* @source Source data
|
||||
* @dest Destination data
|
||||
* @length Size of source data in bytes
|
||||
* Return: 0 on success, negative value on failure
|
||||
*/
|
||||
int sign_enc_data_block(u8 *source, unsigned int length, u8 *signature, u8 *key);
|
||||
int encrypt_data_block(u8 *source, u8 *dest, unsigned int length);
|
||||
|
||||
/**
|
||||
* Encrypt a block of data
|
||||
* decrypt_data_block - Decrypt a block of data
|
||||
*
|
||||
* \param source Source data
|
||||
* \param length Size of source data
|
||||
* \param key AES128 encryption key
|
||||
* @source Source data
|
||||
* @dest Destination data
|
||||
* @length Size of source data in bytes
|
||||
* Return: 0 on success, negative value on failure
|
||||
*/
|
||||
int encrypt_data_block(u8 *source, unsigned int length, u8 *key);
|
||||
|
||||
/**
|
||||
* Decrypt a block of data
|
||||
*
|
||||
* \param source Source data
|
||||
* \param length Size of source data
|
||||
* \param key AES128 encryption key
|
||||
*/
|
||||
int decrypt_data_block(u8 *source, unsigned int length, u8 *key);
|
||||
int decrypt_data_block(u8 *source, u8 *dest, unsigned int length);
|
||||
|
||||
#endif /* #ifndef _CRYPTO_H_ */
|
||||
|
@ -448,6 +448,9 @@ enum win_color_depth_id {
|
||||
#define LVS_OUTPUT_POLARITY_LOW BIT(28)
|
||||
#define LSC0_OUTPUT_POLARITY_LOW BIT(24)
|
||||
|
||||
/* DC_COM_PIN_OUTPUT_POLARITY3 0x309 */
|
||||
#define LSPI_OUTPUT_POLARITY_LOW BIT(8)
|
||||
|
||||
/* DC_COM_PIN_OUTPUT_SELECT6 0x31a */
|
||||
#define LDC_OUTPUT_SELECT_V_PULSE1 BIT(14) /* 100b */
|
||||
|
||||
|
@ -17,8 +17,22 @@ struct fuse_regs {
|
||||
u32 fa; /* 0x148: FUSE_FA */
|
||||
u32 reserved3[21]; /* 0x14C - 0x19C: */
|
||||
u32 security_mode; /* 0x1A0: FUSE_SECURITY_MODE */
|
||||
u32 sbk[4]; /* 0x1A4 - 0x1B4 */
|
||||
};
|
||||
|
||||
/* Defines the supported operating modes */
|
||||
enum fuse_operating_mode {
|
||||
MODE_UNDEFINED = 0,
|
||||
MODE_PRODUCTION = 3,
|
||||
MODE_ODM_PRODUCTION_SECURE = 4,
|
||||
MODE_ODM_PRODUCTION_OPEN = 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes fuse hardware
|
||||
*/
|
||||
void tegra_fuse_init(void);
|
||||
|
||||
/**
|
||||
* Calculate SoC UID
|
||||
*
|
||||
@ -26,4 +40,11 @@ struct fuse_regs {
|
||||
*/
|
||||
unsigned long long tegra_chip_uid(void);
|
||||
|
||||
/**
|
||||
* Gives the current operating mode from fuses
|
||||
*
|
||||
* @return current operating mode
|
||||
*/
|
||||
enum fuse_operating_mode tegra_fuse_get_operation_mode(void);
|
||||
|
||||
#endif /* ifndef _FUSE_H_ */
|
||||
|
@ -10,12 +10,6 @@
|
||||
#define STRAP_OPT_A_RAM_CODE_SHIFT 4
|
||||
#define STRAP_OPT_A_RAM_CODE_MASK (0xf << STRAP_OPT_A_RAM_CODE_SHIFT)
|
||||
|
||||
/* Defines the supported operating modes */
|
||||
enum fuse_operating_mode {
|
||||
MODE_PRODUCTION = 3,
|
||||
MODE_UNDEFINED,
|
||||
};
|
||||
|
||||
/* Defines the CMAC-AES-128 hash length in 32 bit words. (128 bits = 4 words) */
|
||||
enum {
|
||||
HASH_LENGTH = 4
|
||||
@ -125,7 +119,6 @@ union scratch3_reg {
|
||||
int warmboot_save_sdram_params(void);
|
||||
|
||||
int warmboot_prepare_code(u32 seg_address, u32 seg_length);
|
||||
int sign_data_block(u8 *source, u32 length, u8 *signature);
|
||||
void wb_start(void); /* Start of WB assembly code */
|
||||
void wb_end(void); /* End of WB assembly code */
|
||||
|
||||
|
@ -17,7 +17,9 @@ config TEGRA_CLKRST
|
||||
|
||||
config TEGRA_CRYPTO
|
||||
bool "Tegra AES128 crypto module"
|
||||
select DM_AES
|
||||
select AES
|
||||
select TEGRA_AES
|
||||
|
||||
config TEGRA_GP_PADCTRL
|
||||
bool
|
||||
|
@ -37,6 +37,14 @@ int tegra_get_chip(void)
|
||||
return rev;
|
||||
}
|
||||
|
||||
u32 tegra_get_major_version(void)
|
||||
{
|
||||
struct apb_misc_gp_ctlr *gp =
|
||||
(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
|
||||
|
||||
return (readl(&gp->hidrev) & HIDREV_MAJORPREV_MASK) >> HIDREV_MAJORPREV_SHIFT;
|
||||
}
|
||||
|
||||
int tegra_get_sku_info(void)
|
||||
{
|
||||
int sku_id;
|
||||
|
@ -71,6 +71,7 @@ void powerup_cpu(void);
|
||||
void reset_A9_cpu(int reset);
|
||||
void start_cpu(u32 reset_vector);
|
||||
int tegra_get_chip(void);
|
||||
u32 tegra_get_major_version(void);
|
||||
int tegra_get_sku_info(void);
|
||||
int tegra_get_chip_sku(void);
|
||||
void adjust_pllp_out_freqs(void);
|
||||
|
@ -4,164 +4,68 @@
|
||||
* (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com>
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/arch-tegra/crypto.h>
|
||||
#include "uboot_aes.h"
|
||||
|
||||
static u8 zero_key[16];
|
||||
|
||||
#define AES_CMAC_CONST_RB 0x87 /* from RFC 4493, Figure 2.2 */
|
||||
|
||||
enum security_op {
|
||||
SECURITY_SIGN = 1 << 0, /* Sign the data */
|
||||
SECURITY_ENCRYPT = 1 << 1, /* Encrypt the data */
|
||||
SECURITY_DECRYPT = 1 << 2, /* Dectypt the data */
|
||||
};
|
||||
|
||||
/**
|
||||
* Shift a vector left by one bit
|
||||
*
|
||||
* \param in Input vector
|
||||
* \param out Output vector
|
||||
* \param size Length of vector in bytes
|
||||
*/
|
||||
static void left_shift_vector(u8 *in, u8 *out, int size)
|
||||
{
|
||||
int carry = 0;
|
||||
int i;
|
||||
|
||||
for (i = size - 1; i >= 0; i--) {
|
||||
out[i] = (in[i] << 1) | carry;
|
||||
carry = in[i] >> 7; /* get most significant bit */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a block of data, putting the result into dst.
|
||||
*
|
||||
* \param key Input AES key, length AES128_KEY_LENGTH
|
||||
* \param key_schedule Expanded key to use
|
||||
* \param src Source data of length 'num_aes_blocks' blocks
|
||||
* \param dst Destination buffer, length AES128_KEY_LENGTH
|
||||
* \param num_aes_blocks Number of AES blocks to encrypt
|
||||
*/
|
||||
static void sign_object(u8 *key, u8 *key_schedule, u8 *src, u8 *dst,
|
||||
u32 num_aes_blocks)
|
||||
{
|
||||
u8 tmp_data[AES128_KEY_LENGTH];
|
||||
u8 iv[AES128_KEY_LENGTH] = {0};
|
||||
u8 left[AES128_KEY_LENGTH];
|
||||
u8 k1[AES128_KEY_LENGTH];
|
||||
u8 *cbc_chain_data;
|
||||
unsigned int i;
|
||||
|
||||
cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
|
||||
|
||||
/* compute K1 constant needed by AES-CMAC calculation */
|
||||
for (i = 0; i < AES128_KEY_LENGTH; i++)
|
||||
tmp_data[i] = 0;
|
||||
|
||||
aes_cbc_encrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv,
|
||||
tmp_data, left, 1);
|
||||
|
||||
left_shift_vector(left, k1, sizeof(left));
|
||||
|
||||
if ((left[0] >> 7) != 0) /* get MSB of L */
|
||||
k1[AES128_KEY_LENGTH - 1] ^= AES_CMAC_CONST_RB;
|
||||
|
||||
/* compute the AES-CMAC value */
|
||||
for (i = 0; i < num_aes_blocks; i++) {
|
||||
/* Apply the chain data */
|
||||
aes_apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
|
||||
|
||||
/* for the final block, XOR K1 into the IV */
|
||||
if (i == num_aes_blocks - 1)
|
||||
aes_apply_cbc_chain_data(tmp_data, k1, tmp_data);
|
||||
|
||||
/* encrypt the AES block */
|
||||
aes_encrypt(AES128_KEY_LENGTH, tmp_data,
|
||||
key_schedule, dst);
|
||||
|
||||
debug("sign_obj: block %d of %d\n", i, num_aes_blocks);
|
||||
|
||||
/* Update pointers for next loop. */
|
||||
cbc_chain_data = dst;
|
||||
src += AES128_KEY_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt, encrypt or sign a block of data (depending on security mode).
|
||||
*
|
||||
* \param key Input AES key, length AES128_KEY_LENGTH
|
||||
* \param oper Security operations mask to perform (enum security_op)
|
||||
* \param src Source data
|
||||
* \param length Size of source data
|
||||
* \param sig_dst Destination address for signature, AES128_KEY_LENGTH bytes
|
||||
*/
|
||||
static int tegra_crypto_core(u8 *key, enum security_op oper, u8 *src,
|
||||
u32 length, u8 *sig_dst)
|
||||
{
|
||||
u32 num_aes_blocks;
|
||||
u8 key_schedule[AES128_EXPAND_KEY_LENGTH];
|
||||
u8 iv[AES128_KEY_LENGTH] = {0};
|
||||
|
||||
debug("%s: length = %d\n", __func__, length);
|
||||
|
||||
aes_expand_key(key, AES128_KEY_LENGTH, key_schedule);
|
||||
|
||||
num_aes_blocks = (length + AES128_KEY_LENGTH - 1) / AES128_KEY_LENGTH;
|
||||
|
||||
if (oper & SECURITY_DECRYPT) {
|
||||
/* Perform this in place, resulting in src being decrypted. */
|
||||
debug("%s: begin decryption\n", __func__);
|
||||
aes_cbc_decrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv, src,
|
||||
src, num_aes_blocks);
|
||||
debug("%s: end decryption\n", __func__);
|
||||
}
|
||||
|
||||
if (oper & SECURITY_ENCRYPT) {
|
||||
/* Perform this in place, resulting in src being encrypted. */
|
||||
debug("%s: begin encryption\n", __func__);
|
||||
aes_cbc_encrypt_blocks(AES128_KEY_LENGTH, key_schedule, iv, src,
|
||||
src, num_aes_blocks);
|
||||
debug("%s: end encryption\n", __func__);
|
||||
}
|
||||
|
||||
if (oper & SECURITY_SIGN) {
|
||||
/* encrypt the data, overwriting the result in signature. */
|
||||
debug("%s: begin signing\n", __func__);
|
||||
sign_object(key, key_schedule, src, sig_dst, num_aes_blocks);
|
||||
debug("%s: end signing\n", __func__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tegra crypto group
|
||||
*/
|
||||
int sign_data_block(u8 *source, unsigned int length, u8 *signature)
|
||||
{
|
||||
return tegra_crypto_core(zero_key, SECURITY_SIGN, source,
|
||||
length, signature);
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
/* Only one AES engine should be present */
|
||||
ret = uclass_get_device(UCLASS_AES, 0, &dev);
|
||||
if (ret) {
|
||||
log_err("%s: failed to get tegra_aes: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dm_aes_select_key_slot(dev, 128, TEGRA_AES_SLOT_SBK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return dm_aes_cmac(dev, source, signature,
|
||||
DIV_ROUND_UP(length, AES_BLOCK_LENGTH));
|
||||
}
|
||||
|
||||
int sign_enc_data_block(u8 *source, unsigned int length, u8 *signature, u8 *key)
|
||||
int encrypt_data_block(u8 *source, u8 *dest, unsigned int length)
|
||||
{
|
||||
return tegra_crypto_core(key, SECURITY_SIGN, source,
|
||||
length, signature);
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
/* Only one AES engine should be present */
|
||||
ret = uclass_get_device(UCLASS_AES, 0, &dev);
|
||||
if (ret) {
|
||||
log_err("%s: failed to get tegra_aes: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dm_aes_select_key_slot(dev, 128, TEGRA_AES_SLOT_SBK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return dm_aes_cbc_encrypt(dev, (u8 *)AES_ZERO_BLOCK, source, dest,
|
||||
DIV_ROUND_UP(length, AES_BLOCK_LENGTH));
|
||||
}
|
||||
|
||||
int encrypt_data_block(u8 *source, unsigned int length, u8 *key)
|
||||
int decrypt_data_block(u8 *source, u8 *dest, unsigned int length)
|
||||
{
|
||||
return tegra_crypto_core(key, SECURITY_ENCRYPT, source,
|
||||
length, NULL);
|
||||
}
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
int decrypt_data_block(u8 *source, unsigned int length, u8 *key)
|
||||
{
|
||||
return tegra_crypto_core(key, SECURITY_DECRYPT, source,
|
||||
length, NULL);
|
||||
/* Only one AES engine should be present */
|
||||
ret = uclass_get_device(UCLASS_AES, 0, &dev);
|
||||
if (ret) {
|
||||
log_err("%s: failed to get tegra_aes: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dm_aes_select_key_slot(dev, 128, TEGRA_AES_SLOT_SBK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return dm_aes_cbc_decrypt(dev, (u8 *)AES_ZERO_BLOCK, source, dest,
|
||||
DIV_ROUND_UP(length, AES_BLOCK_LENGTH));
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ static u32 tegra_fuse_readl(unsigned long offset)
|
||||
return readl(NV_PA_FUSE_BASE + offset);
|
||||
}
|
||||
|
||||
static void tegra_fuse_init(void)
|
||||
void tegra_fuse_init(void)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
@ -49,8 +49,11 @@ static void tegra_fuse_init(void)
|
||||
* this bit fuse region will not work.
|
||||
*/
|
||||
reg = readl_relaxed(NV_PA_CLK_RST_BASE + 0x48);
|
||||
reg |= BIT(28);
|
||||
writel(reg, NV_PA_CLK_RST_BASE + 0x48);
|
||||
|
||||
if (reg & BIT(28))
|
||||
return;
|
||||
|
||||
writel(reg | BIT(28), NV_PA_CLK_RST_BASE + 0x48);
|
||||
|
||||
clock_enable(PERIPH_ID_FUSE);
|
||||
udelay(2);
|
||||
@ -148,3 +151,57 @@ unsigned long long tegra_chip_uid(void)
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
static int tegra_is_production_mode_fuse_set(struct fuse_regs *fuse)
|
||||
{
|
||||
return readl(&fuse->production_mode);
|
||||
}
|
||||
|
||||
static int tegra_is_odm_production_mode_fuse_set(struct fuse_regs *fuse)
|
||||
{
|
||||
return readl(&fuse->security_mode);
|
||||
}
|
||||
|
||||
static int tegra_is_failure_analysis_mode(struct fuse_regs *fuse)
|
||||
{
|
||||
return readl(&fuse->fa);
|
||||
}
|
||||
|
||||
static int tegra_is_sbk_zeroes(struct fuse_regs *fuse)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
if (readl(&fuse->sbk[i]))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tegra_is_production_mode(struct fuse_regs *fuse)
|
||||
{
|
||||
if (!tegra_get_major_version())
|
||||
return 1;
|
||||
|
||||
return !tegra_is_failure_analysis_mode(fuse) &&
|
||||
tegra_is_production_mode_fuse_set(fuse);
|
||||
}
|
||||
|
||||
enum fuse_operating_mode tegra_fuse_get_operation_mode(void)
|
||||
{
|
||||
struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
|
||||
|
||||
tegra_fuse_init();
|
||||
|
||||
if (tegra_is_production_mode(fuse)) {
|
||||
if (!tegra_is_odm_production_mode_fuse_set(fuse))
|
||||
return MODE_PRODUCTION;
|
||||
else
|
||||
if (tegra_is_sbk_zeroes(fuse))
|
||||
return MODE_ODM_PRODUCTION_OPEN;
|
||||
else
|
||||
return MODE_ODM_PRODUCTION_SECURE;
|
||||
}
|
||||
|
||||
return MODE_UNDEFINED;
|
||||
}
|
||||
|
@ -9,12 +9,10 @@
|
||||
#include <vsprintf.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/arch-tegra/crypto.h>
|
||||
#include <asm/arch-tegra/fuse.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
|
||||
@ -26,29 +24,25 @@ 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);
|
||||
encrypted = tegra_fuse_get_operation_mode() == MODE_ODM_PRODUCTION_SECURE;
|
||||
|
||||
if (encrypted) {
|
||||
ret = decrypt_data_block(sbct, SBCT_LENGTH, sbk);
|
||||
ret = decrypt_data_block(sbct, sbct, SBCT_LENGTH);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
ret = encrypt_data_block(ebt, ebt_size, sbk);
|
||||
ret = encrypt_data_block(ebt, ebt, ebt_size);
|
||||
if (ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk);
|
||||
ret = sign_data_block(ebt, ebt_size, ebt_hash);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
@ -61,12 +55,12 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
|
||||
bct_tbl->bootloader[0].length = ebt_size;
|
||||
|
||||
if (encrypted) {
|
||||
ret = encrypt_data_block(sbct, SBCT_LENGTH, sbk);
|
||||
ret = encrypt_data_block(sbct, sbct, SBCT_LENGTH);
|
||||
if (ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = sign_enc_data_block(sbct, SBCT_LENGTH, bct_hash, sbk);
|
||||
ret = sign_data_block(sbct, SBCT_LENGTH, bct_hash);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
|
@ -54,6 +54,10 @@ config TARGET_SEABOARD
|
||||
select TEGRA_LP0
|
||||
select TEGRA_PMU
|
||||
|
||||
config TARGET_SAMSUNG_N1
|
||||
bool "Samsung Tegra20 N1 board"
|
||||
select BOARD_LATE_INIT
|
||||
|
||||
config TARGET_STAR
|
||||
bool "LG Tegra20 Star board"
|
||||
select BOARD_LATE_INIT
|
||||
@ -92,6 +96,7 @@ source "board/compal/paz00/Kconfig"
|
||||
source "board/acer/picasso/Kconfig"
|
||||
source "board/avionic-design/plutux/Kconfig"
|
||||
source "board/nvidia/seaboard/Kconfig"
|
||||
source "board/samsung/n1/Kconfig"
|
||||
source "board/lg/star/Kconfig"
|
||||
source "board/avionic-design/tec/Kconfig"
|
||||
source "board/asus/transformer-t20/Kconfig"
|
||||
|
@ -9,12 +9,10 @@
|
||||
#include <vsprintf.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/arch-tegra/crypto.h>
|
||||
#include <asm/arch-tegra/fuse.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
|
||||
@ -25,7 +23,6 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
|
||||
{
|
||||
struct nvboot_config_table *bct_tbl = NULL;
|
||||
u8 ebt_hash[AES128_KEY_LENGTH] = { 0 };
|
||||
u8 sbk[AES128_KEY_LENGTH] = { 0 };
|
||||
u8 *bct_hash = bct;
|
||||
bool encrypted;
|
||||
int ret;
|
||||
@ -34,22 +31,19 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
|
||||
|
||||
ebt_size = roundup(ebt_size, EBT_ALIGNMENT);
|
||||
|
||||
memcpy(sbk, (u8 *)(bct + BCT_LENGTH),
|
||||
NVBOOT_CMAC_AES_HASH_LENGTH * 4);
|
||||
|
||||
encrypted = memcmp(&sbk, &nosbk, AES128_KEY_LENGTH);
|
||||
encrypted = tegra_fuse_get_operation_mode() == MODE_ODM_PRODUCTION_SECURE;
|
||||
|
||||
if (encrypted) {
|
||||
ret = decrypt_data_block(bct, BCT_LENGTH, sbk);
|
||||
ret = decrypt_data_block(bct, bct, BCT_LENGTH);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
ret = encrypt_data_block(ebt, ebt_size, sbk);
|
||||
ret = encrypt_data_block(ebt, ebt, ebt_size);
|
||||
if (ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk);
|
||||
ret = sign_data_block(ebt, ebt_size, ebt_hash);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
@ -62,12 +56,12 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
|
||||
bct_tbl->bootloader[0].length = ebt_size;
|
||||
|
||||
if (encrypted) {
|
||||
ret = encrypt_data_block(bct, BCT_LENGTH, sbk);
|
||||
ret = encrypt_data_block(bct, bct, BCT_LENGTH);
|
||||
if (ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = sign_enc_data_block(bct, BCT_LENGTH, bct_hash, sbk);
|
||||
ret = sign_data_block(bct, BCT_LENGTH, bct_hash);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <asm/arch-tegra/pmc.h>
|
||||
#include <asm/arch-tegra/fuse.h>
|
||||
#include <asm/arch-tegra/warmboot.h>
|
||||
#include <asm/arch-tegra/crypto.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
@ -182,98 +183,36 @@ int warmboot_save_sdram_params(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 get_major_version(void)
|
||||
static void determine_crypto_options(int *is_encrypted, int *is_signed)
|
||||
{
|
||||
u32 major_id;
|
||||
struct apb_misc_gp_ctlr *gp =
|
||||
(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
|
||||
|
||||
major_id = (readl(&gp->hidrev) & HIDREV_MAJORPREV_MASK) >>
|
||||
HIDREV_MAJORPREV_SHIFT;
|
||||
return major_id;
|
||||
}
|
||||
|
||||
static int is_production_mode_fuse_set(struct fuse_regs *fuse)
|
||||
{
|
||||
return readl(&fuse->production_mode);
|
||||
}
|
||||
|
||||
static int is_odm_production_mode_fuse_set(struct fuse_regs *fuse)
|
||||
{
|
||||
return readl(&fuse->security_mode);
|
||||
}
|
||||
|
||||
static int is_failure_analysis_mode(struct fuse_regs *fuse)
|
||||
{
|
||||
return readl(&fuse->fa);
|
||||
}
|
||||
|
||||
static int ap20_is_odm_production_mode(void)
|
||||
{
|
||||
struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
|
||||
|
||||
if (!is_failure_analysis_mode(fuse) &&
|
||||
is_odm_production_mode_fuse_set(fuse))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ap20_is_production_mode(void)
|
||||
{
|
||||
struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE;
|
||||
|
||||
if (get_major_version() == 0)
|
||||
return 1;
|
||||
|
||||
if (!is_failure_analysis_mode(fuse) &&
|
||||
is_production_mode_fuse_set(fuse) &&
|
||||
!is_odm_production_mode_fuse_set(fuse))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum fuse_operating_mode fuse_get_operation_mode(void)
|
||||
{
|
||||
u32 chip_id;
|
||||
struct apb_misc_gp_ctlr *gp =
|
||||
(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE;
|
||||
|
||||
chip_id = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >>
|
||||
HIDREV_CHIPID_SHIFT;
|
||||
if (chip_id == CHIPID_TEGRA20) {
|
||||
if (ap20_is_odm_production_mode()) {
|
||||
printf("!! odm_production_mode is not supported !!\n");
|
||||
return MODE_UNDEFINED;
|
||||
} else
|
||||
if (ap20_is_production_mode())
|
||||
return MODE_PRODUCTION;
|
||||
else
|
||||
return MODE_UNDEFINED;
|
||||
}
|
||||
return MODE_UNDEFINED;
|
||||
}
|
||||
|
||||
static void determine_crypto_options(int *is_encrypted, int *is_signed,
|
||||
int *use_zero_key)
|
||||
{
|
||||
switch (fuse_get_operation_mode()) {
|
||||
switch (tegra_fuse_get_operation_mode()) {
|
||||
case MODE_ODM_PRODUCTION_SECURE:
|
||||
*is_encrypted = 1;
|
||||
*is_signed = 1;
|
||||
break;
|
||||
case MODE_ODM_PRODUCTION_OPEN:
|
||||
case MODE_PRODUCTION:
|
||||
*is_encrypted = 0;
|
||||
*is_signed = 1;
|
||||
*use_zero_key = 1;
|
||||
break;
|
||||
case MODE_UNDEFINED:
|
||||
default:
|
||||
*is_encrypted = 0;
|
||||
*is_signed = 0;
|
||||
*use_zero_key = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int sign_wb_code(u32 start, u32 length, int use_zero_key)
|
||||
static int encrypt_wb_code(u8 *source, u8 *destination, u32 length)
|
||||
{
|
||||
source += offsetof(struct wb_header, random_aes_block);
|
||||
destination += offsetof(struct wb_header, random_aes_block);
|
||||
length -= offsetof(struct wb_header, random_aes_block);
|
||||
|
||||
return encrypt_data_block(source, destination, length);
|
||||
}
|
||||
|
||||
static int sign_wb_code(u32 start, u32 length)
|
||||
{
|
||||
int err;
|
||||
u8 *source; /* Pointer to source */
|
||||
@ -295,10 +234,9 @@ int warmboot_prepare_code(u32 seg_address, u32 seg_length)
|
||||
struct wb_header *dst_header; /* Pointer to dest WB header */
|
||||
int is_encrypted; /* Segment is encrypted */
|
||||
int is_signed; /* Segment is signed */
|
||||
int use_zero_key; /* Use key of all zeros */
|
||||
|
||||
/* Determine crypto options. */
|
||||
determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key);
|
||||
determine_crypto_options(&is_encrypted, &is_signed);
|
||||
|
||||
/* Get the actual code limits. */
|
||||
length = roundup(((u32)wb_end - (u32)wb_start), 16);
|
||||
@ -346,18 +284,15 @@ int warmboot_prepare_code(u32 seg_address, u32 seg_length)
|
||||
dst_header->entry_point = NV_WB_RUN_ADDRESS;
|
||||
dst_header->code_length = length;
|
||||
|
||||
if (is_encrypted) {
|
||||
printf("!!!! Encryption is not supported !!!!\n");
|
||||
dst_header->length_insecure = 0;
|
||||
err = -EACCES;
|
||||
goto fail;
|
||||
} else
|
||||
/* copy the wb code directly following dst_header. */
|
||||
memcpy((char *)(dst_header+1), (char *)wb_start, length);
|
||||
if (is_encrypted)
|
||||
encrypt_wb_code((u8 *)wb_start, (u8 *)dst_header,
|
||||
length + sizeof(struct wb_header));
|
||||
else
|
||||
/* copy the wb code directly following dst_header */
|
||||
memcpy((char *)(dst_header + 1), (char *)wb_start, length);
|
||||
|
||||
if (is_signed)
|
||||
err = sign_wb_code(seg_address, dst_header->length_insecure,
|
||||
use_zero_key);
|
||||
err = sign_wb_code(seg_address, dst_header->length_insecure);
|
||||
|
||||
fail:
|
||||
if (err)
|
||||
|
@ -16,6 +16,10 @@ config TARGET_CARDHU
|
||||
bool "NVIDIA Tegra30 Cardhu evaluation board"
|
||||
select BOARD_LATE_INIT
|
||||
|
||||
config TARGET_CHAGALL
|
||||
bool "Pegatron Tegra30 Chagall board"
|
||||
select BOARD_LATE_INIT
|
||||
|
||||
config TARGET_COLIBRI_T30
|
||||
bool "Toradex Colibri T30 board"
|
||||
select BOARD_LATE_INIT
|
||||
@ -64,6 +68,7 @@ config SYS_SOC
|
||||
source "board/toradex/apalis_t30/Kconfig"
|
||||
source "board/nvidia/beaver/Kconfig"
|
||||
source "board/nvidia/cardhu/Kconfig"
|
||||
source "board/pegatron/chagall/Kconfig"
|
||||
source "board/toradex/colibri_t30/Kconfig"
|
||||
source "board/htc/endeavoru/Kconfig"
|
||||
source "board/asus/grouper/Kconfig"
|
||||
|
@ -9,12 +9,10 @@
|
||||
#include <vsprintf.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/arch-tegra/crypto.h>
|
||||
#include <asm/arch-tegra/fuse.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
|
||||
@ -25,7 +23,6 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
|
||||
{
|
||||
struct nvboot_config_table *bct_tbl = NULL;
|
||||
u8 ebt_hash[AES128_KEY_LENGTH] = { 0 };
|
||||
u8 sbk[AES128_KEY_LENGTH] = { 0 };
|
||||
u8 *bct_hash = bct;
|
||||
bool encrypted;
|
||||
int ret;
|
||||
@ -34,22 +31,19 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
|
||||
|
||||
ebt_size = roundup(ebt_size, EBT_ALIGNMENT);
|
||||
|
||||
memcpy(sbk, (u8 *)(bct + BCT_LENGTH),
|
||||
NVBOOT_CMAC_AES_HASH_LENGTH * 4);
|
||||
|
||||
encrypted = memcmp(&sbk, &nosbk, AES128_KEY_LENGTH);
|
||||
encrypted = tegra_fuse_get_operation_mode() == MODE_ODM_PRODUCTION_SECURE;
|
||||
|
||||
if (encrypted) {
|
||||
ret = decrypt_data_block(bct, BCT_LENGTH, sbk);
|
||||
ret = decrypt_data_block(bct, bct, BCT_LENGTH);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
ret = encrypt_data_block(ebt, ebt_size, sbk);
|
||||
ret = encrypt_data_block(ebt, ebt, ebt_size);
|
||||
if (ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = sign_enc_data_block(ebt, ebt_size, ebt_hash, sbk);
|
||||
ret = sign_data_block(ebt, ebt_size, ebt_hash);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
@ -62,12 +56,12 @@ static int bct_patch(u8 *bct, u8 *ebt, u32 ebt_size)
|
||||
bct_tbl->bootloader[0].length = ebt_size;
|
||||
|
||||
if (encrypted) {
|
||||
ret = encrypt_data_block(bct, BCT_LENGTH, sbk);
|
||||
ret = encrypt_data_block(bct, bct, BCT_LENGTH);
|
||||
if (ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = sign_enc_data_block(bct, BCT_LENGTH, bct_hash, sbk);
|
||||
ret = sign_data_block(bct, BCT_LENGTH, bct_hash);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
|
13
board/pegatron/chagall/Kconfig
Normal file
13
board/pegatron/chagall/Kconfig
Normal file
@ -0,0 +1,13 @@
|
||||
if TARGET_CHAGALL
|
||||
|
||||
config SYS_BOARD
|
||||
default "chagall"
|
||||
|
||||
config SYS_VENDOR
|
||||
default "pegatron"
|
||||
|
||||
config TEGRA_BOARD_STRING
|
||||
string "Default Tegra board name"
|
||||
default "Pegatron Chagall"
|
||||
|
||||
endif
|
7
board/pegatron/chagall/MAINTAINERS
Normal file
7
board/pegatron/chagall/MAINTAINERS
Normal file
@ -0,0 +1,7 @@
|
||||
CHAGALL BOARD
|
||||
M: Svyatoslav Ryhel <clamor95@gmail.com>
|
||||
S: Maintained
|
||||
F: arch/arm/dts/tegra30-pegatron-chagall.dts
|
||||
F: board/pegatron/chagall/
|
||||
F: configs/chagall_defconfig
|
||||
F: doc/board/pegatron/chagall.rst
|
11
board/pegatron/chagall/Makefile
Normal file
11
board/pegatron/chagall/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2010-2012
|
||||
# NVIDIA Corporation <www.nvidia.com>
|
||||
#
|
||||
# (C) Copyright 2021
|
||||
# Svyatoslav Ryhel <clamor95@gmail.com>
|
||||
|
||||
obj-$(CONFIG_XPL_BUILD) += chagall-spl.o
|
||||
|
||||
obj-y += chagall.o
|
41
board/pegatron/chagall/chagall-spl.c
Normal file
41
board/pegatron/chagall/chagall-spl.c
Normal file
@ -0,0 +1,41 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Chagall SPL stage configuration
|
||||
*
|
||||
* (C) Copyright 2010-2013
|
||||
* NVIDIA Corporation <www.nvidia.com>
|
||||
*
|
||||
* (C) Copyright 2021
|
||||
* Svyatoslav Ryhel <clamor95@gmail.com>
|
||||
*/
|
||||
|
||||
#include <asm/arch/tegra.h>
|
||||
#include <asm/arch-tegra/tegra_i2c.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define TPS65911_I2C_ADDR (0x2D << 1)
|
||||
#define TPS65911_VDDCTRL_OP_REG 0x28
|
||||
#define TPS65911_VDDCTRL_SR_REG 0x27
|
||||
#define TPS65911_VDDCTRL_OP_DATA (0x2400 | TPS65911_VDDCTRL_OP_REG)
|
||||
#define TPS65911_VDDCTRL_SR_DATA (0x0100 | TPS65911_VDDCTRL_SR_REG)
|
||||
|
||||
#define TPS62361B_I2C_ADDR (0x60 << 1)
|
||||
#define TPS62361B_SET3_REG 0x03
|
||||
#define TPS62361B_SET3_DATA (0x4600 | TPS62361B_SET3_REG)
|
||||
|
||||
void pmic_enable_cpu_vdd(void)
|
||||
{
|
||||
/* Set VDD_CORE to 1.200V. */
|
||||
tegra_i2c_ll_write(TPS62361B_I2C_ADDR, TPS62361B_SET3_DATA);
|
||||
|
||||
udelay(1000);
|
||||
|
||||
/*
|
||||
* Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus.
|
||||
* First set VDD to 1.0125V, then enable the VDD regulator.
|
||||
*/
|
||||
tegra_i2c_ll_write(TPS65911_I2C_ADDR, TPS65911_VDDCTRL_OP_DATA);
|
||||
udelay(1000);
|
||||
tegra_i2c_ll_write(TPS65911_I2C_ADDR, TPS65911_VDDCTRL_SR_DATA);
|
||||
udelay(10 * 1000);
|
||||
}
|
23
board/pegatron/chagall/chagall.c
Normal file
23
board/pegatron/chagall/chagall.c
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2010-2013
|
||||
* NVIDIA Corporation <www.nvidia.com>
|
||||
*
|
||||
* (C) Copyright 2021
|
||||
* Svyatoslav Ryhel <clamor95@gmail.com>
|
||||
*/
|
||||
|
||||
/* Chagall derives from Cardhu board */
|
||||
|
||||
#include <fdt_support.h>
|
||||
|
||||
#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_OF_BOARD_SETUP)
|
||||
int ft_board_setup(void *blob, struct bd_info *bd)
|
||||
{
|
||||
/* Remove TrustZone nodes */
|
||||
fdt_del_node_and_alias(blob, "/firmware");
|
||||
fdt_del_node_and_alias(blob, "/reserved-memory/trustzone@bfe00000");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
9
board/pegatron/chagall/chagall.env
Normal file
9
board/pegatron/chagall/chagall.env
Normal file
@ -0,0 +1,9 @@
|
||||
button_cmd_0_name=Volume Down
|
||||
button_cmd_0=bootmenu
|
||||
|
||||
bootmenu_0=mount external storage=usb start && ums 0 mmc 1; bootmenu
|
||||
bootmenu_1=fastboot=echo Starting Fastboot protocol ...; fastboot usb 0; bootmenu
|
||||
bootmenu_2=reboot RCM=enterrcm
|
||||
bootmenu_3=reboot=reset
|
||||
bootmenu_4=power off=poweroff
|
||||
bootmenu_delay=-1
|
13
board/samsung/n1/Kconfig
Normal file
13
board/samsung/n1/Kconfig
Normal file
@ -0,0 +1,13 @@
|
||||
if TARGET_SAMSUNG_N1
|
||||
|
||||
config SYS_BOARD
|
||||
default "n1"
|
||||
|
||||
config SYS_VENDOR
|
||||
default "samsung"
|
||||
|
||||
config TEGRA_BOARD_STRING
|
||||
string "Default Tegra board name"
|
||||
default "Samsung N1"
|
||||
|
||||
endif
|
9
board/samsung/n1/MAINTAINERS
Normal file
9
board/samsung/n1/MAINTAINERS
Normal file
@ -0,0 +1,9 @@
|
||||
N1 BOARD
|
||||
M: Ion Agorria <ion@agorria.com>
|
||||
M: Svyatoslav Ryhel <clamor95@gmail.com>
|
||||
S: Maintained
|
||||
F: arch/arm/dts/tegra20-samsung-bose.dts
|
||||
F: arch/arm/dts/tegra20-samsung-n1.dts
|
||||
F: board/samsung/n1/
|
||||
F: configs/n1_defconfig
|
||||
F: doc/board/samsung/n1.rst
|
6
board/samsung/n1/bose.config
Normal file
6
board/samsung/n1/bose.config
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_DEFAULT_DEVICE_TREE="tegra20-samsung-bose"
|
||||
CONFIG_SYS_PROMPT="Tegra20 (Bose) # "
|
||||
# CONFIG_VIDEO_BRIDGE_SAMSUNG_CMC623 is not set
|
||||
# CONFIG_BACKLIGHT_SAMSUNG_CMC623 is not set
|
||||
# CONFIG_VIDEO_LCD_SONY_L4F00430T01 is not set
|
||||
CONFIG_VIDEO_LCD_SAMSUNG_S6E63M0=y
|
16
board/samsung/n1/n1.env
Normal file
16
board/samsung/n1/n1.env
Normal file
@ -0,0 +1,16 @@
|
||||
#include <env/nvidia/prod_upd.env>
|
||||
|
||||
button_cmd_0_name=Volume Down
|
||||
button_cmd_0=bootmenu
|
||||
|
||||
boot_block_size_r=0x80000
|
||||
boot_block_size=0x400
|
||||
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=reboot RCM=enterrcm
|
||||
bootmenu_4=reboot=reset
|
||||
bootmenu_5=power off=poweroff
|
||||
bootmenu_delay=-1
|
80
configs/chagall_defconfig
Normal file
80
configs/chagall_defconfig
Normal file
@ -0,0 +1,80 @@
|
||||
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_NR_DRAM_BANKS=2
|
||||
CONFIG_ENV_SOURCE_FILE="chagall"
|
||||
CONFIG_ENV_SIZE=0x3000
|
||||
CONFIG_ENV_OFFSET=0xFFFFD000
|
||||
CONFIG_DEFAULT_DEVICE_TREE="tegra30-pegatron-chagall"
|
||||
CONFIG_SPL_STACK=0x800ffffc
|
||||
CONFIG_SPL_TEXT_BASE=0x80108000
|
||||
CONFIG_SYS_LOAD_ADDR=0x82000000
|
||||
CONFIG_TEGRA30=y
|
||||
CONFIG_TARGET_CHAGALL=y
|
||||
CONFIG_BUTTON_CMD=y
|
||||
CONFIG_BOOTDELAY=0
|
||||
CONFIG_AUTOBOOT_KEYED=y
|
||||
CONFIG_AUTOBOOT_KEYED_CTRLC=y
|
||||
CONFIG_OF_BOARD_SETUP=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=2084
|
||||
CONFIG_SPL_FOOTPRINT_LIMIT=y
|
||||
CONFIG_SPL_MAX_FOOTPRINT=0x8000
|
||||
# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
|
||||
CONFIG_SPL_HAVE_INIT_STACK=y
|
||||
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="Tegra30 (Chagall) # "
|
||||
# CONFIG_CMD_BOOTEFI_BOOTMGR is not set
|
||||
CONFIG_CMD_BOOTMENU=y
|
||||
# CONFIG_CMD_IMI is not set
|
||||
CONFIG_CMD_GPIO=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_SYS_I2C_TEGRA=y
|
||||
CONFIG_BUTTON_KEYBOARD=y
|
||||
CONFIG_DM_PMIC=y
|
||||
CONFIG_DM_PMIC_TPS65910=y
|
||||
CONFIG_DM_REGULATOR=y
|
||||
CONFIG_DM_REGULATOR_FIXED=y
|
||||
CONFIG_DM_REGULATOR_TPS65911=y
|
||||
CONFIG_PWM_TEGRA=y
|
||||
CONFIG_SYS_NS16550=y
|
||||
CONFIG_SYSRESET_TPS65910=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_EHCI_TEGRA=y
|
||||
CONFIG_USB_KEYBOARD=y
|
||||
CONFIG_USB_GADGET=y
|
||||
CONFIG_CI_UDC=y
|
||||
CONFIG_VIDEO=y
|
||||
# CONFIG_VIDEO_LOGO is not set
|
||||
CONFIG_VIDEO_BRIDGE=y
|
||||
CONFIG_VIDEO_BRIDGE_LVDS_CODEC=y
|
||||
CONFIG_VIDEO_TEGRA=y
|
92
configs/n1_defconfig
Normal file
92
configs/n1_defconfig
Normal file
@ -0,0 +1,92 @@
|
||||
CONFIG_ARM=y
|
||||
CONFIG_ARCH_TEGRA=y
|
||||
CONFIG_SUPPORT_PASSING_ATAGS=y
|
||||
CONFIG_CMDLINE_TAG=y
|
||||
CONFIG_INITRD_TAG=y
|
||||
CONFIG_TEXT_BASE=0x00110000
|
||||
CONFIG_NR_DRAM_BANKS=2
|
||||
CONFIG_ENV_SOURCE_FILE="n1"
|
||||
CONFIG_ENV_SIZE=0x3000
|
||||
CONFIG_ENV_OFFSET=0xFFFFD000
|
||||
CONFIG_DEFAULT_DEVICE_TREE="tegra20-samsung-n1"
|
||||
CONFIG_SPL_STACK=0xffffc
|
||||
CONFIG_SPL_TEXT_BASE=0x00108000
|
||||
CONFIG_SYS_LOAD_ADDR=0x2000000
|
||||
CONFIG_TEGRA20=y
|
||||
CONFIG_TARGET_SAMSUNG_N1=y
|
||||
CONFIG_TEGRA_ENABLE_UARTB=y
|
||||
CONFIG_CMD_EBTUPDATE=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=2085
|
||||
CONFIG_SPL_FOOTPRINT_LIMIT=y
|
||||
CONFIG_SPL_MAX_FOOTPRINT=0x8000
|
||||
# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
|
||||
CONFIG_SPL_HAVE_INIT_STACK=y
|
||||
CONFIG_SPL_SYS_MALLOC=y
|
||||
CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y
|
||||
CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x90000
|
||||
CONFIG_SPL_SYS_MALLOC_SIZE=0x10000
|
||||
CONFIG_SYS_PROMPT="Tegra20 (N1) # "
|
||||
# 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_EXT4_WRITE=y
|
||||
# CONFIG_SPL_DOS_PARTITION is not set
|
||||
# CONFIG_SPL_EFI_PARTITION is not set
|
||||
CONFIG_ENV_OVERWRITE=y
|
||||
CONFIG_ENV_IS_IN_MMC=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=0x11000000
|
||||
CONFIG_FASTBOOT_BUF_SIZE=0x5000000
|
||||
CONFIG_FASTBOOT_FLASH=y
|
||||
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
|
||||
CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
|
||||
CONFIG_DM_I2C_GPIO=y
|
||||
CONFIG_SYS_I2C_TEGRA=y
|
||||
CONFIG_BUTTON_KEYBOARD=y
|
||||
CONFIG_DM_PMIC=y
|
||||
CONFIG_DM_PMIC_MAX8907=y
|
||||
CONFIG_DM_REGULATOR=y
|
||||
CONFIG_DM_REGULATOR_MAX8907=y
|
||||
CONFIG_DM_REGULATOR_FIXED=y
|
||||
CONFIG_SYS_NS16550=y
|
||||
CONFIG_TEGRA20_SLINK=y
|
||||
CONFIG_SYSRESET_MAX8907=y
|
||||
CONFIG_USB=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_EHCI_TEGRA=y
|
||||
CONFIG_USB_ULPI_VIEWPORT=y
|
||||
CONFIG_USB_ULPI=y
|
||||
CONFIG_USB_KEYBOARD=y
|
||||
CONFIG_USB_GADGET=y
|
||||
CONFIG_USB_GADGET_MANUFACTURER="Samsung"
|
||||
CONFIG_USB_GADGET_VENDOR_NUM=0x04e8
|
||||
CONFIG_USB_GADGET_PRODUCT_NUM=0x685F
|
||||
CONFIG_CI_UDC=y
|
||||
CONFIG_VIDEO=y
|
||||
# CONFIG_VIDEO_LOGO is not set
|
||||
# CONFIG_VIDEO_BPP8 is not set
|
||||
CONFIG_VIDEO_BRIDGE=y
|
||||
CONFIG_VIDEO_TEGRA=y
|
||||
CONFIG_VIDEO_BRIDGE_SAMSUNG_CMC623=y
|
||||
CONFIG_BACKLIGHT_SAMSUNG_CMC623=y
|
||||
CONFIG_VIDEO_LCD_SONY_L4F00430T01=y
|
@ -47,6 +47,7 @@ Board-specific doc
|
||||
nxp/index
|
||||
openpiton/index
|
||||
ouya/index
|
||||
pegatron/index
|
||||
phytec/index
|
||||
purism/index
|
||||
qualcomm/index
|
||||
|
41
doc/board/pegatron/chagall.rst
Normal file
41
doc/board/pegatron/chagall.rst
Normal file
@ -0,0 +1,41 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
U-Boot for the Pegatron Chagall tablet
|
||||
======================================
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
||||
- Build U-Boot
|
||||
- Boot
|
||||
|
||||
Build U-Boot
|
||||
------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ export CROSS_COMPILE=arm-none-eabi-
|
||||
$ make chagall_defconfig
|
||||
$ make
|
||||
|
||||
After the build succeeds, you will obtain the final ``u-boot-dtb-tegra.bin``
|
||||
image, ready for loading.
|
||||
|
||||
Boot
|
||||
----
|
||||
|
||||
Currently, U-Boot can be preloaded into RAM via the Fusée Gelée. To enter
|
||||
RCM protocol use ``power`` and ``volume up`` key combination from powered
|
||||
off device. The host PC should recognize an APX device.
|
||||
|
||||
Built U-Boot ``u-boot-dtb-tegra.bin`` can be loaded from fusee-tools
|
||||
directory with
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ ./run_bootloader.sh -s T30 -t ./bct/chagall.bct
|
||||
|
||||
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 loading, the
|
||||
device will enter bootmenu. Bootmenu contains entries to mount MicroSD and eMMC
|
||||
as mass storage, fastboot, reboot, reboot RCM and poweroff.
|
9
doc/board/pegatron/index.rst
Normal file
9
doc/board/pegatron/index.rst
Normal file
@ -0,0 +1,9 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
Pegatron
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
chagall
|
@ -8,3 +8,4 @@ Samsung
|
||||
|
||||
axy17lte
|
||||
e850-96
|
||||
n1
|
||||
|
51
doc/board/samsung/n1.rst
Normal file
51
doc/board/samsung/n1.rst
Normal file
@ -0,0 +1,51 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
U-Boot for the Samsung N1 device family
|
||||
=======================================
|
||||
|
||||
``DISCLAMER!`` Moving your Samsung Galaxy R (GT-I9103) or Samsung Captivate Glide
|
||||
(SGH-i927) to use U-Boot assumes replacement of the sboot. Vendor android firmwares
|
||||
will no longer be able to run on the device. This replacement IS reversible.
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
||||
- Build U-Boot
|
||||
- Boot
|
||||
|
||||
Build U-Boot
|
||||
------------
|
||||
|
||||
Device support is implemented by applying config fragment to a generic board
|
||||
defconfig. Generic board defconfig is suitable for Samsung Galaxy R (GT-I9103)
|
||||
while Samsung Captivate Glide (SGH-i927) support is provided by applying
|
||||
``bose.config`` fragment.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ export CROSS_COMPILE=arm-none-eabi-
|
||||
$ make n1_defconfig bose.config # For Captivate Glide
|
||||
$ make
|
||||
|
||||
After the build succeeds, you will obtain the final ``u-boot-dtb-tegra.bin``
|
||||
image, ready for further processing.
|
||||
|
||||
Boot
|
||||
----
|
||||
|
||||
Currently, U-Boot can be preloaded into RAM via the NvFlash. To enter
|
||||
RCM protocol use ``home`` and ``volume up`` for Galaxy R and ``volume down``
|
||||
and ``volume up`` Captivate Glide key combination plus plugging usb in.
|
||||
The host PC should recognize an APX device.
|
||||
|
||||
Built U-Boot ``u-boot-dtb-tegra.bin`` can be loaded from fusee-tools
|
||||
directory with
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ ./utils/nvflash_t20 --setbct --bct ./bct/i927.bct --configfile ./utils/flash.cfg --bl u-boot-dtb-tegra.bin --sbk (in form of 0xABCDABCD 4 times) --sync # For Captivate Glide
|
||||
|
||||
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 loading, the
|
||||
device will enter bootmenu. Bootmenu contains entries to mount MicroSD and eMMC
|
||||
as mass storage, fastboot, reboot, reboot RCM and poweroff.
|
@ -10,4 +10,6 @@ source "drivers/crypto/aspeed/Kconfig"
|
||||
|
||||
source "drivers/crypto/nuvoton/Kconfig"
|
||||
|
||||
source "drivers/crypto/tegra/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
@ -10,3 +10,4 @@ obj-y += fsl/
|
||||
obj-y += hash/
|
||||
obj-y += aspeed/
|
||||
obj-y += nuvoton/
|
||||
obj-y += tegra/
|
||||
|
7
drivers/crypto/tegra/Kconfig
Normal file
7
drivers/crypto/tegra/Kconfig
Normal file
@ -0,0 +1,7 @@
|
||||
config TEGRA_AES
|
||||
bool "Support the Tegra AES"
|
||||
depends on DM_AES
|
||||
help
|
||||
This provides a means to encrypt and decrypt data using the Tegra
|
||||
Bit Stream Engine for Video/Audio. Also may provide a mean to
|
||||
encrypt/decrypt/sign using already loaded device SBK.
|
3
drivers/crypto/tegra/Makefile
Normal file
3
drivers/crypto/tegra/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
obj-$(CONFIG_$(PHASE_)TEGRA_AES) += tegra_aes.o
|
591
drivers/crypto/tegra/tegra_aes.c
Normal file
591
drivers/crypto/tegra/tegra_aes.c
Normal file
@ -0,0 +1,591 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Driver for NVIDIA Tegra AES hardware engine residing inside the Bit Stream Engine
|
||||
* for Video (BSEV) hardware block and Bit Stream Engine for Audio (BSEA).
|
||||
*
|
||||
* The programming sequence for this engine is with the help of commands which travel
|
||||
* via a command queue residing between the CPU and the BSEV/BSEA block.
|
||||
*
|
||||
* The hardware key table length is 64 bytes and each key slot divided as follows:
|
||||
* 1. Key - 32 bytes
|
||||
* 2. Original IV - 16 bytes
|
||||
* 3. Updated IV - 16 bytes
|
||||
*
|
||||
* The engine has 4 slots in T20/T30 in which 0th contains SBK loaded by bootrom,
|
||||
* vendor bootloaders tend to clear this slot so that anything booted after can't
|
||||
* use the SBK. This is relevant for U-Boot's chainloaded from these vendor bootloaders.
|
||||
*
|
||||
* Copyright (c) 2010-2011, NVIDIA Corporation
|
||||
* Copyright (c) 2025, Ion Agorria.
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
#include <linux/delay.h>
|
||||
#include <clk.h>
|
||||
#include <reset.h>
|
||||
#include <uboot_aes.h>
|
||||
|
||||
#include <asm/arch-tegra/crypto.h>
|
||||
#include <asm/arch-tegra/fuse.h>
|
||||
|
||||
/* Make sure pointers will fit register size for AES engine */
|
||||
static_assert(sizeof(void *) == sizeof(u32));
|
||||
|
||||
#define IRAM_BASE 0x40000000
|
||||
|
||||
#define TEGRA_AES_DMA_BUFFER_SIZE (0x4000 / AES_BLOCK_LENGTH)
|
||||
#define TEGRA_AES_HW_MAX_KEY_LENGTH AES256_KEY_LENGTH
|
||||
#define TEGRA_AES_HW_TABLE_LENGTH (TEGRA_AES_HW_MAX_KEY_LENGTH + AES_BLOCK_LENGTH * 2)
|
||||
#define TEGRA_AES_IRAM_MAX_ADDR (IRAM_BASE | TEGRA_AES_KEYTABLEADDR_FIELD)
|
||||
|
||||
#define TEGRA_AES_BUSY_TIMEOUT_MS 1000
|
||||
|
||||
/* Registers */
|
||||
#define TEGRA_AES_ICMDQUE_WR 0x000
|
||||
#define TEGRA_AES_CMDQUE_CONTROL 0x008
|
||||
#define TEGRA_AES_INTR_STATUS 0x018
|
||||
#define TEGRA_AES_INT_ENB 0x040
|
||||
#define TEGRA_AES_BSE_CFG 0x044
|
||||
#define TEGRA_AES_IRAM_ACCESS_CFG 0x0a0
|
||||
#define TEGRA_AES_SECURE_DEST_ADDR 0x100
|
||||
#define TEGRA_AES_SECURE_INPUT_SELECT 0x104
|
||||
#define TEGRA_AES_SECURE_CONFIG 0x108
|
||||
#define TEGRA_AES_SECURE_CONFIG_EXT 0x10c
|
||||
|
||||
/* Register field macros */
|
||||
#define TEGRA_AES_ENGINE_BUSY_FIELD BIT(0)
|
||||
#define TEGRA_AES_ICQ_EMPTY_FIELD BIT(3)
|
||||
#define TEGRA_AES_DMA_BUSY_FIELD BIT(23)
|
||||
#define TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD BIT(15)
|
||||
#define TEGRA_AES_KEYTABLEADDR_FIELD (BIT(17) - 1)
|
||||
#define TEGRA_AES_SECURE_KEY_INDEX_SHIFT 20
|
||||
#define TEGRA_AES_SECURE_KEY_INDEX_FIELD (0x1f << TEGRA_AES_SECURE_KEY_INDEX_SHIFT)
|
||||
#define TEGRA_AES_SECURE_CTR_CNT_SHIFT 16
|
||||
#define TEGRA_AES_SECURE_CTR_CNT_FIELD (0xffff << TEGRA_AES_SECURE_CTR_CNT_SHIFT)
|
||||
#define TEGRA_AES_BSE_MODE_FIELD 0x1f
|
||||
#define TEGRA_AES_BSE_LITTLE_ENDIAN_FIELD BIT(10)
|
||||
#define TEGRA_AES_CMDQ_OPCODE_SHIFT 26
|
||||
#define TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD BIT(1)
|
||||
#define TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD BIT(4)
|
||||
#define TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD BIT(5)
|
||||
#define TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT 28
|
||||
#define TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT 16
|
||||
#define TEGRA_AES_SECURE_INPUT_IV_FIELD BIT(10)
|
||||
#define TEGRA_AES_SECURE_INPUT_HASH_ENB_FIELD BIT(2)
|
||||
#define TEGRA_AES_SECURE_CORE_SEL_SHIFT 9
|
||||
#define TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT 7
|
||||
#define TEGRA_AES_SECURE_XOR_POS_SHIFT 3
|
||||
#define TEGRA_AES_INT_ERROR_MASK 0x6ff000
|
||||
|
||||
/* Commands for BSEV/BSEA */
|
||||
#define TEGRA_AES_CMD_BLKSTARTENGINE 0x0e
|
||||
#define TEGRA_AES_CMD_DMASETUP 0x10
|
||||
#define TEGRA_AES_CMD_DMACOMPLETE 0x11
|
||||
#define TEGRA_AES_CMD_SETTABLE 0x15
|
||||
|
||||
/* Flags for mode */
|
||||
#define TEGRA_AES_MODE_ENCRYPT BIT(0)
|
||||
#define TEGRA_AES_MODE_CBC BIT(1)
|
||||
#define TEGRA_AES_MODE_UPDATE_IV BIT(2)
|
||||
#define TEGRA_AES_MODE_HASH BIT(3)
|
||||
|
||||
struct tegra_aes_priv {
|
||||
void *regs;
|
||||
void *iram_addr;
|
||||
|
||||
struct reset_ctl reset_ctl;
|
||||
struct reset_ctl reset_ctl_vde;
|
||||
|
||||
struct clk *clk;
|
||||
struct clk *clk_parent;
|
||||
|
||||
u8 current_key_size;
|
||||
bool sbk_available;
|
||||
};
|
||||
|
||||
static bool tegra_aes_is_busy(struct tegra_aes_priv *priv, bool dma_wait)
|
||||
{
|
||||
u32 value = readl(priv->regs + TEGRA_AES_INTR_STATUS);
|
||||
bool engine_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD;
|
||||
bool non_empty_queue = !(value & TEGRA_AES_ICQ_EMPTY_FIELD);
|
||||
bool dma_busy = dma_wait && (value & TEGRA_AES_DMA_BUSY_FIELD);
|
||||
|
||||
log_debug("%s - e:%d q:%d dma:%d\n", __func__, engine_busy, non_empty_queue, dma_busy);
|
||||
|
||||
return engine_busy || non_empty_queue || dma_busy;
|
||||
}
|
||||
|
||||
static u32 tegra_aes_check_error(struct tegra_aes_priv *priv)
|
||||
{
|
||||
u32 value = readl(priv->regs + TEGRA_AES_INTR_STATUS) & TEGRA_AES_INT_ERROR_MASK;
|
||||
|
||||
if (value) {
|
||||
writel(TEGRA_AES_INT_ERROR_MASK, priv->regs + TEGRA_AES_INTR_STATUS);
|
||||
log_debug("%s 0x%x\n", __func__, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int tegra_aes_wait_for_idle_dma(struct tegra_aes_priv *priv, bool dma_wait)
|
||||
{
|
||||
ulong start = get_timer(0);
|
||||
|
||||
while (tegra_aes_is_busy(priv, dma_wait)) {
|
||||
if (get_timer(start) > TEGRA_AES_BUSY_TIMEOUT_MS) {
|
||||
log_err("%s: TIMEOUT!!!\n", __func__);
|
||||
break;
|
||||
}
|
||||
mdelay(5);
|
||||
}
|
||||
|
||||
if (tegra_aes_check_error(priv))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_aes_wait_for_idle(struct tegra_aes_priv *priv)
|
||||
{
|
||||
return tegra_aes_wait_for_idle_dma(priv, 1);
|
||||
}
|
||||
|
||||
static int tegra_aes_configure(struct tegra_aes_priv *priv)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if (tegra_aes_wait_for_idle(priv))
|
||||
return -1;
|
||||
|
||||
/* IRAM config */
|
||||
writel(0, priv->regs + TEGRA_AES_IRAM_ACCESS_CFG);
|
||||
|
||||
/* Reset interrupts bits, or engine will hang on next operation */
|
||||
writel(0xFFFFFFFF, priv->regs + TEGRA_AES_INTR_STATUS);
|
||||
|
||||
/* Set interrupts */
|
||||
writel(0, priv->regs + TEGRA_AES_INT_ENB);
|
||||
|
||||
/* Configure CMDQUE */
|
||||
value = readl(priv->regs + TEGRA_AES_CMDQUE_CONTROL);
|
||||
value |= TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD |
|
||||
TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD |
|
||||
TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD;
|
||||
writel(value, priv->regs + TEGRA_AES_CMDQUE_CONTROL);
|
||||
|
||||
value = readl(priv->regs + TEGRA_AES_SECURE_CONFIG_EXT);
|
||||
value &= ~TEGRA_AES_SECURE_CTR_CNT_FIELD;
|
||||
writel(value, priv->regs + TEGRA_AES_SECURE_CONFIG_EXT);
|
||||
|
||||
/* Configure BSE */
|
||||
value = readl(priv->regs + TEGRA_AES_BSE_CFG);
|
||||
value &= ~TEGRA_AES_BSE_MODE_FIELD;
|
||||
value |= TEGRA_AES_BSE_LITTLE_ENDIAN_FIELD;
|
||||
writel(value, priv->regs + TEGRA_AES_BSE_CFG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_aes_select_key_slot(struct tegra_aes_priv *priv, u32 key_size, u8 slot)
|
||||
{
|
||||
if (tegra_aes_wait_for_idle(priv))
|
||||
return -1;
|
||||
|
||||
if (key_size < (AES128_KEY_LENGTH * 8) ||
|
||||
key_size > (TEGRA_AES_HW_MAX_KEY_LENGTH * 8))
|
||||
return -EINVAL;
|
||||
|
||||
priv->current_key_size = key_size;
|
||||
|
||||
/* Select the key slot */
|
||||
u32 value = readl(priv->regs + TEGRA_AES_SECURE_CONFIG);
|
||||
|
||||
value &= ~TEGRA_AES_SECURE_KEY_INDEX_FIELD;
|
||||
value |= (slot << TEGRA_AES_SECURE_KEY_INDEX_SHIFT);
|
||||
writel(value, priv->regs + TEGRA_AES_SECURE_CONFIG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_aes_call_engine(struct tegra_aes_priv *priv, u8 *src, u8 *dst,
|
||||
u32 nblocks, u32 mode)
|
||||
{
|
||||
u32 value;
|
||||
const u32 ICMDQ_LENGTH = 4;
|
||||
u32 cmdq[ICMDQ_LENGTH];
|
||||
|
||||
log_debug("%s: 0x%p -> 0x%p blocks %d mode 0x%x\n", __func__,
|
||||
src, dst, nblocks, mode);
|
||||
|
||||
if (!nblocks) {
|
||||
log_warning("%s: called with 0 blocks!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tegra_aes_configure(priv))
|
||||
return -1;
|
||||
|
||||
/* Configure Secure Input */
|
||||
value = 1 << TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT |
|
||||
priv->current_key_size << TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT;
|
||||
|
||||
if (mode & TEGRA_AES_MODE_UPDATE_IV)
|
||||
value |= TEGRA_AES_SECURE_INPUT_IV_FIELD;
|
||||
if (mode & TEGRA_AES_MODE_HASH)
|
||||
value |= TEGRA_AES_SECURE_INPUT_HASH_ENB_FIELD;
|
||||
if (mode & TEGRA_AES_MODE_CBC) {
|
||||
value |= ((mode & TEGRA_AES_MODE_ENCRYPT) ? 2 : 3) <<
|
||||
TEGRA_AES_SECURE_XOR_POS_SHIFT;
|
||||
value |= ((mode & TEGRA_AES_MODE_ENCRYPT) ? 2 : 3) <<
|
||||
TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT;
|
||||
value |= ((mode & TEGRA_AES_MODE_ENCRYPT) ? 1 : 0) <<
|
||||
TEGRA_AES_SECURE_CORE_SEL_SHIFT;
|
||||
} else {
|
||||
/* ECB */
|
||||
value |= ((mode & TEGRA_AES_MODE_ENCRYPT) ? 1 : 0) <<
|
||||
TEGRA_AES_SECURE_CORE_SEL_SHIFT;
|
||||
}
|
||||
|
||||
writel(value, priv->regs + TEGRA_AES_SECURE_INPUT_SELECT);
|
||||
|
||||
/* Set destination address (doing in-place at IRAM) */
|
||||
writel((u32)priv->iram_addr, priv->regs + TEGRA_AES_SECURE_DEST_ADDR);
|
||||
|
||||
/* Copy src data to IRAM */
|
||||
if (src != priv->iram_addr)
|
||||
memcpy(priv->iram_addr, src, nblocks * AES_BLOCK_LENGTH);
|
||||
|
||||
/* Run ICMD commands */
|
||||
cmdq[0] = TEGRA_AES_CMD_DMASETUP << TEGRA_AES_CMDQ_OPCODE_SHIFT;
|
||||
cmdq[1] = (u32)priv->iram_addr;
|
||||
cmdq[2] = TEGRA_AES_CMD_BLKSTARTENGINE << TEGRA_AES_CMDQ_OPCODE_SHIFT | (nblocks - 1);
|
||||
cmdq[3] = TEGRA_AES_CMD_DMACOMPLETE << TEGRA_AES_CMDQ_OPCODE_SHIFT;
|
||||
|
||||
for (int i = 0; i < ICMDQ_LENGTH; i++) {
|
||||
tegra_aes_wait_for_idle_dma(priv, (ICMDQ_LENGTH - 1) == i);
|
||||
writel(cmdq[i], priv->regs + TEGRA_AES_ICMDQUE_WR);
|
||||
}
|
||||
|
||||
if (tegra_aes_wait_for_idle(priv))
|
||||
return -1;
|
||||
|
||||
/* Put the result from IRAM to destination if not hashing */
|
||||
if (dst != priv->iram_addr && !(mode & TEGRA_AES_MODE_HASH))
|
||||
memcpy(dst, priv->iram_addr, nblocks * AES_BLOCK_LENGTH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_aes_process_blocks(struct udevice *dev, u8 *iv, u8 *src,
|
||||
u8 *dst, u32 num_aes_blocks, u32 mode)
|
||||
{
|
||||
struct tegra_aes_priv *priv = dev_get_priv(dev);
|
||||
|
||||
log_debug("%s: 0x%p -> 0x%p blocks %d mode 0x%x\n",
|
||||
__func__, src, dst, num_aes_blocks, mode);
|
||||
|
||||
if (!num_aes_blocks) {
|
||||
log_warning("%s: called with 0 blocks!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load initial IV if CBC mode */
|
||||
if (mode & TEGRA_AES_MODE_CBC) {
|
||||
if (tegra_aes_call_engine(priv, iv, priv->iram_addr, 1, TEGRA_AES_MODE_CBC))
|
||||
return -1;
|
||||
|
||||
/* Add update IV flag */
|
||||
mode |= TEGRA_AES_MODE_UPDATE_IV;
|
||||
}
|
||||
|
||||
/* Process blocks by calling engine several times per dma buffer size */
|
||||
while (num_aes_blocks > 0) {
|
||||
u32 blocks = min(num_aes_blocks, (u32)TEGRA_AES_DMA_BUFFER_SIZE);
|
||||
|
||||
if (tegra_aes_call_engine(priv, src, dst, blocks, mode))
|
||||
return -1;
|
||||
|
||||
num_aes_blocks -= blocks;
|
||||
src += blocks * AES_BLOCK_LENGTH;
|
||||
dst += blocks * AES_BLOCK_LENGTH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_aes_ops_available_key_slots(struct udevice *dev)
|
||||
{
|
||||
return 4; /* 4 slots in Tegra20 and Tegra30 */
|
||||
}
|
||||
|
||||
static int tegra_aes_ops_select_key_slot(struct udevice *dev, u32 key_size, u8 slot)
|
||||
{
|
||||
struct tegra_aes_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (slot == TEGRA_AES_SLOT_SBK && !priv->sbk_available) {
|
||||
log_warning("%s: SBK not available!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return tegra_aes_select_key_slot(priv, key_size, slot);
|
||||
}
|
||||
|
||||
static int tegra_aes_ops_set_key_for_key_slot(struct udevice *dev, u32 key_size,
|
||||
u8 *key, u8 slot)
|
||||
{
|
||||
struct tegra_aes_priv *priv = dev_get_priv(dev);
|
||||
const u8 SUBCMD_CRYPTO_TABLE_SEL = 0x3;
|
||||
const u8 SUBCMD_KEY_TABLE_SEL = 0x8;
|
||||
const u8 CMDQ_KEYTABLEADDR_SHIFT = 0;
|
||||
const u8 CMDQ_KEYTABLEID_SHIFT = 17;
|
||||
const u8 CMDQ_TABLESEL_SHIFT = 24;
|
||||
u32 value, addr;
|
||||
|
||||
log_debug("%s: slot %d\n", __func__, slot);
|
||||
|
||||
if (tegra_aes_configure(priv))
|
||||
return -1;
|
||||
|
||||
if (key_size < (AES128_KEY_LENGTH * 8) ||
|
||||
key_size > (TEGRA_AES_HW_MAX_KEY_LENGTH * 8))
|
||||
return -EINVAL;
|
||||
|
||||
if (slot == TEGRA_AES_SLOT_SBK)
|
||||
log_debug("%s: SBK slot being set!\n", __func__);
|
||||
|
||||
/* Clear and copy data to IRAM */
|
||||
memset(priv->iram_addr, 0, TEGRA_AES_HW_TABLE_LENGTH);
|
||||
memcpy(priv->iram_addr, key, key_size / 8);
|
||||
|
||||
/* Mask the addr */
|
||||
addr = ((u32)priv->iram_addr) & TEGRA_AES_KEYTABLEADDR_FIELD;
|
||||
|
||||
/* Command for engine to load AES key from IRAM */
|
||||
value = TEGRA_AES_CMD_SETTABLE << TEGRA_AES_CMDQ_OPCODE_SHIFT |
|
||||
SUBCMD_CRYPTO_TABLE_SEL << CMDQ_TABLESEL_SHIFT |
|
||||
(SUBCMD_KEY_TABLE_SEL | slot) << CMDQ_KEYTABLEID_SHIFT |
|
||||
addr << CMDQ_KEYTABLEADDR_SHIFT;
|
||||
writel(value, priv->regs + TEGRA_AES_ICMDQUE_WR);
|
||||
|
||||
return tegra_aes_wait_for_idle(priv);
|
||||
}
|
||||
|
||||
static int tegra_aes_ops_aes_ecb_encrypt(struct udevice *dev, u8 *src, u8 *dst,
|
||||
u32 num_aes_blocks)
|
||||
{
|
||||
return tegra_aes_process_blocks(dev, NULL, src, dst, num_aes_blocks,
|
||||
TEGRA_AES_MODE_ENCRYPT);
|
||||
}
|
||||
|
||||
static int tegra_aes_ops_aes_ecb_decrypt(struct udevice *dev, u8 *src, u8 *dst,
|
||||
u32 num_aes_blocks)
|
||||
{
|
||||
return tegra_aes_process_blocks(dev, NULL, src, dst, num_aes_blocks, 0);
|
||||
}
|
||||
|
||||
static int tegra_aes_ops_aes_cbc_encrypt(struct udevice *dev, u8 *iv, u8 *src,
|
||||
u8 *dst, u32 num_aes_blocks)
|
||||
{
|
||||
return tegra_aes_process_blocks(dev, iv, src, dst, num_aes_blocks,
|
||||
TEGRA_AES_MODE_CBC | TEGRA_AES_MODE_ENCRYPT);
|
||||
}
|
||||
|
||||
static int tegra_aes_ops_aes_cbc_decrypt(struct udevice *dev, u8 *iv, u8 *src,
|
||||
u8 *dst, u32 num_aes_blocks)
|
||||
{
|
||||
return tegra_aes_process_blocks(dev, iv, src, dst, num_aes_blocks,
|
||||
TEGRA_AES_MODE_CBC);
|
||||
}
|
||||
|
||||
static void tegra_aes_test_loaded_sbk(struct udevice *dev)
|
||||
{
|
||||
struct tegra_aes_priv *priv = dev_get_priv(dev);
|
||||
enum fuse_operating_mode opmode = tegra_fuse_get_operation_mode();
|
||||
const u8 ZERO_KEY_CIPHERTEXT[AES_BLOCK_LENGTH] = {
|
||||
0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b,
|
||||
0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34, 0x2b, 0x2e
|
||||
};
|
||||
|
||||
/* Encrypt a zero block, we use ECB so that we only care about SBK and not the IV */
|
||||
memset(priv->iram_addr, 0, AES_BLOCK_LENGTH);
|
||||
tegra_aes_select_key_slot(priv, 128, TEGRA_AES_SLOT_SBK);
|
||||
tegra_aes_call_engine(priv, priv->iram_addr, priv->iram_addr, 1, TEGRA_AES_MODE_ENCRYPT);
|
||||
|
||||
/* Evaluate the result of engine operation */
|
||||
if (!memcmp(priv->iram_addr, AES_ZERO_BLOCK, AES_BLOCK_LENGTH)) {
|
||||
log_err("%s: engine is not operational! (opmode 0x%x)\n", __func__, opmode);
|
||||
} else if (!memcmp(priv->iram_addr, ZERO_KEY_CIPHERTEXT, AES_BLOCK_LENGTH)) {
|
||||
if (opmode == MODE_ODM_PRODUCTION_SECURE) {
|
||||
log_warning("%s: SBK is zero or is cleared from engine! (opmode 0x%x)\n",
|
||||
__func__, opmode);
|
||||
} else {
|
||||
log_debug("%s - SBK is zero and available! (opmode 0x%x)\n",
|
||||
__func__, opmode);
|
||||
priv->sbk_available = true;
|
||||
}
|
||||
} else {
|
||||
if (opmode == MODE_ODM_PRODUCTION_SECURE) {
|
||||
log_debug("%s: SBK is available! (opmode 0x%x)\n", __func__, opmode);
|
||||
priv->sbk_available = true;
|
||||
} else {
|
||||
log_warning("%s: SBK is not zero and should be! (opmode 0x%x)\n",
|
||||
__func__, opmode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int tegra_aes_hw_init(struct udevice *dev)
|
||||
{
|
||||
struct tegra_aes_priv *priv = dev_get_priv(dev);
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
if (priv->clk_parent) {
|
||||
ret = reset_assert(&priv->reset_ctl_vde);
|
||||
if (ret) {
|
||||
log_debug("%s: VDE reset assert failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = reset_assert(&priv->reset_ctl);
|
||||
if (ret) {
|
||||
log_debug("%s: BSE reset assert failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->clk_parent) {
|
||||
ret = clk_enable(priv->clk_parent);
|
||||
if (ret) {
|
||||
log_err("%s: VDE clock enable failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(priv->clk_parent, 50 * 1000000);
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
log_err("%s: VDE clock set rate failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_enable(priv->clk);
|
||||
if (ret) {
|
||||
log_err("%s: BSE clock enable failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->clk_parent) {
|
||||
ret = reset_deassert(&priv->reset_ctl_vde);
|
||||
if (ret) {
|
||||
log_err("%s: VDE reset deassert failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = reset_deassert(&priv->reset_ctl);
|
||||
if (ret) {
|
||||
log_err("%s: BSE reset deassert failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable key schedule generation in hardware */
|
||||
value = readl(priv->regs + TEGRA_AES_SECURE_CONFIG_EXT);
|
||||
value &= ~TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD;
|
||||
writel(value, priv->regs + TEGRA_AES_SECURE_CONFIG_EXT);
|
||||
|
||||
/* Check if SBK is loaded in SBK slot or was erased */
|
||||
priv->sbk_available = false;
|
||||
tegra_aes_test_loaded_sbk(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_aes_probe(struct udevice *dev)
|
||||
{
|
||||
struct tegra_aes_priv *priv = dev_get_priv(dev);
|
||||
fdt_size_t iram_size = 0;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
priv->current_key_size = AES128_KEY_LENGTH;
|
||||
|
||||
priv->regs = dev_read_addr_ptr(dev);
|
||||
if (!priv->regs) {
|
||||
log_err("%s: Cannot find aes reg address, binding failed\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->iram_addr = devfdt_get_addr_size_name_ptr(dev, "iram-buffer", &iram_size);
|
||||
if (!priv->iram_addr) {
|
||||
log_debug("%s: Cannot find iram buffer address, binding failed\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iram_size < TEGRA_AES_DMA_BUFFER_SIZE * AES_BLOCK_LENGTH) {
|
||||
log_debug("%s: Unsupported iram buffer size: 0x%x required: 0x%x\n",
|
||||
__func__, iram_size, TEGRA_AES_DMA_BUFFER_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Make sure the IRAM address is kept block aligned and accessible for slot loading */
|
||||
value = (uint32_t)priv->iram_addr;
|
||||
if ((value & 0xFFF0000F) != IRAM_BASE || value > TEGRA_AES_IRAM_MAX_ADDR) {
|
||||
log_debug("%s: iram buffer must be located inside iram,", __func__);
|
||||
log_debug("AES block aligned and not above 0x%08x, current addr %p\n",
|
||||
(u32)TEGRA_AES_IRAM_MAX_ADDR, priv->iram_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = reset_get_by_name(dev, NULL, &priv->reset_ctl);
|
||||
if (ret) {
|
||||
log_debug("%s: failed to get BSE reset: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(priv->clk)) {
|
||||
log_err("%s: failed to get BSE clock: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* VDE clock and reset required by BSEV */
|
||||
ret = reset_get_by_name(dev, "vde", &priv->reset_ctl_vde);
|
||||
if (ret)
|
||||
log_debug("%s: failed to get VDE reset: %d\n", __func__, ret);
|
||||
|
||||
priv->clk_parent = devm_clk_get(dev, "vde");
|
||||
if (IS_ERR(priv->clk_parent))
|
||||
log_debug("%s: failed to get BSE clock: %d\n", __func__, ret);
|
||||
|
||||
return tegra_aes_hw_init(dev);
|
||||
}
|
||||
|
||||
static const struct aes_ops tegra_aes_ops = {
|
||||
.available_key_slots = tegra_aes_ops_available_key_slots,
|
||||
.select_key_slot = tegra_aes_ops_select_key_slot,
|
||||
.set_key_for_key_slot = tegra_aes_ops_set_key_for_key_slot,
|
||||
.aes_ecb_encrypt = tegra_aes_ops_aes_ecb_encrypt,
|
||||
.aes_ecb_decrypt = tegra_aes_ops_aes_ecb_decrypt,
|
||||
.aes_cbc_encrypt = tegra_aes_ops_aes_cbc_encrypt,
|
||||
.aes_cbc_decrypt = tegra_aes_ops_aes_cbc_decrypt,
|
||||
};
|
||||
|
||||
static const struct udevice_id tegra_aes_ids[] = {
|
||||
{ .compatible = "nvidia,tegra20-bsea" },
|
||||
{ .compatible = "nvidia,tegra20-bsev" },
|
||||
{ .compatible = "nvidia,tegra30-bsea" },
|
||||
{ .compatible = "nvidia,tegra30-bsev" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(tegra_aes) = {
|
||||
.name = "tegra_aes",
|
||||
.id = UCLASS_AES,
|
||||
.of_match = tegra_aes_ids,
|
||||
.probe = tegra_aes_probe,
|
||||
.ops = &tegra_aes_ops,
|
||||
.priv_auto = sizeof(struct tegra_aes_priv),
|
||||
};
|
@ -691,6 +691,23 @@ config VIDEO_LCD_HITACHI_TX18D42VM
|
||||
lcd controller which needs to be initialized over SPI, once that is
|
||||
done they work like a regular LVDS panel.
|
||||
|
||||
config VIDEO_LCD_SONY_L4F00430T01
|
||||
tristate "Sony L4F00430T01 480x800 LCD panel support"
|
||||
depends on PANEL
|
||||
help
|
||||
Say Y here if you want to enable support for Sony L4F00430T01
|
||||
LCD module found in Samsung Galaxy R. The panel has a
|
||||
WVGA resolution (480x800) and is setup over SPI, video
|
||||
data comes from RGB.
|
||||
|
||||
config VIDEO_LCD_SAMSUNG_S6E63M0
|
||||
tristate "Samsung S6E63M0 controller based panel support"
|
||||
depends on PANEL && BACKLIGHT
|
||||
help
|
||||
Say Y here if you want to enable support for Samsung S6E63M0
|
||||
controller found in some panels like on Samsung Captivate Glide.
|
||||
Currently only DBI C panel is implemented.
|
||||
|
||||
config VIDEO_LCD_SPI_CS
|
||||
string "SPI CS pin for LCD related config job"
|
||||
depends on VIDEO_LCD_SSD2828 || VIDEO_LCD_HITACHI_TX18D42VM
|
||||
@ -821,6 +838,13 @@ config BACKLIGHT_LP855x
|
||||
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.
|
||||
|
||||
config BACKLIGHT_SAMSUNG_CMC623
|
||||
bool "Backlight Driver for Samsung CMC623"
|
||||
depends on VIDEO_BRIDGE_SAMSUNG_CMC623
|
||||
help
|
||||
Say Y to enable the backlight driver for Samsung CMC623 image converter
|
||||
chip's PWM output to control backlight brightness.
|
||||
|
||||
source "drivers/video/ti/Kconfig"
|
||||
|
||||
source "drivers/video/exynos/Kconfig"
|
||||
|
@ -33,6 +33,7 @@ obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_LM3532) += lm3532_backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_LP855x) += lp855x_backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_SAMSUNG_CMC623) += cmc623_backlight.o
|
||||
obj-${CONFIG_EXYNOS_FB} += exynos/
|
||||
obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/
|
||||
obj-${CONFIG_VIDEO_STM32} += stm32/
|
||||
@ -74,6 +75,8 @@ 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
|
||||
obj-$(CONFIG_VIDEO_LCD_SONY_L4F00430T01) += sony-l4f00430t01.o
|
||||
obj-$(CONFIG_VIDEO_LCD_SAMSUNG_S6E63M0) += samsung-s6e63m0.o
|
||||
obj-$(CONFIG_VIDEO_MCDE_SIMPLE) += mcde_simple.o
|
||||
obj-${CONFIG_VIDEO_MESON} += meson/
|
||||
obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_dsi.o
|
||||
|
@ -66,3 +66,11 @@ config VIDEO_BRIDGE_LVDS_CODEC
|
||||
help
|
||||
Support for transparent LVDS encoders and decoders that don't
|
||||
require any configuration.
|
||||
|
||||
config VIDEO_BRIDGE_SAMSUNG_CMC623
|
||||
bool "Samsung CMC623 Image Converter driver"
|
||||
depends on VIDEO_BRIDGE && DM_GPIO
|
||||
select DM_I2C
|
||||
help
|
||||
Samsung CMC623 image converter chip driver.
|
||||
Found in several Samsung devices such as N1
|
||||
|
@ -11,3 +11,4 @@ obj-$(CONFIG_VIDEO_BRIDGE_ANALOGIX_ANX6345) += anx6345.o
|
||||
obj-$(CONFIG_VIDEO_BRIDGE_SOLOMON_SSD2825) += ssd2825.o
|
||||
obj-$(CONFIG_VIDEO_BRIDGE_TOSHIBA_TC358768) += tc358768.o
|
||||
obj-$(CONFIG_VIDEO_BRIDGE_LVDS_CODEC) += lvds-codec.o
|
||||
obj-$(CONFIG_VIDEO_BRIDGE_SAMSUNG_CMC623) += cmc623.o
|
||||
|
234
drivers/video/bridge/cmc623.c
Normal file
234
drivers/video/bridge/cmc623.c
Normal file
@ -0,0 +1,234 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2025 Ion Agorria <ion@agorria.com>
|
||||
*/
|
||||
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dm/ofnode_graph.h>
|
||||
#include <i2c.h>
|
||||
#include <log.h>
|
||||
#include <backlight.h>
|
||||
#include <panel.h>
|
||||
#include <video_bridge.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/math64.h>
|
||||
#include <power/regulator.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
static const char * const cmc623_supplies[] = {
|
||||
"vdd3v0-supply", "vdd1v2-supply", "vddio1v8-supply"
|
||||
};
|
||||
|
||||
struct cmc623_priv {
|
||||
struct udevice *panel;
|
||||
struct display_timing timing;
|
||||
|
||||
struct udevice *supplies[ARRAY_SIZE(cmc623_supplies)];
|
||||
|
||||
struct gpio_desc enable_gpio; /* also known as FAILSAFE */
|
||||
struct gpio_desc bypass_gpio;
|
||||
};
|
||||
|
||||
static int cmc623_attach(struct udevice *dev)
|
||||
{
|
||||
struct cmc623_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
/* Perform panel setup */
|
||||
ret = panel_enable_backlight(priv->panel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmc623_set_backlight(struct udevice *dev, int percent)
|
||||
{
|
||||
struct cmc623_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return panel_set_backlight(priv->panel, percent);
|
||||
}
|
||||
|
||||
static int cmc623_panel_timings(struct udevice *dev, struct display_timing *timing)
|
||||
{
|
||||
struct cmc623_priv *priv = dev_get_priv(dev);
|
||||
|
||||
memcpy(timing, &priv->timing, sizeof(*timing));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmc623_hw_init(struct udevice *dev)
|
||||
{
|
||||
struct cmc623_priv *priv = dev_get_priv(dev);
|
||||
struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
int i, ret;
|
||||
|
||||
/* enable supplies */
|
||||
for (i = 0; i < ARRAY_SIZE(cmc623_supplies); i++) {
|
||||
ret = regulator_set_enable_if_allowed(priv->supplies[i], 1);
|
||||
if (ret) {
|
||||
log_debug("%s: cannot enable %s %d\n", __func__,
|
||||
cmc623_supplies[i], ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
mdelay(10);
|
||||
|
||||
ret = dm_gpio_set_value(&uc_priv->reset, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: error at reset = 1 (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dm_gpio_set_value(&priv->enable_gpio, 0);
|
||||
if (ret) {
|
||||
log_debug("%s: error at enable = 0 (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dm_gpio_set_value(&priv->bypass_gpio, 0);
|
||||
if (ret) {
|
||||
log_debug("%s: error at bypass = 0 (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dm_gpio_set_value(&uc_priv->sleep, 0);
|
||||
if (ret) {
|
||||
log_debug("%s: error at sleep = 0 (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
udelay(2000);
|
||||
|
||||
ret = dm_gpio_set_value(&priv->enable_gpio, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: error at enable = 1 (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
udelay(2000);
|
||||
|
||||
ret = dm_gpio_set_value(&priv->bypass_gpio, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: error at bypass = 1 (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
udelay(2000);
|
||||
|
||||
ret = dm_gpio_set_value(&uc_priv->sleep, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: error at sleep = 1 (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
udelay(2000);
|
||||
|
||||
ret = dm_gpio_set_value(&uc_priv->reset, 0);
|
||||
if (ret) {
|
||||
log_debug("%s: error at sleep = 0 (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mdelay(10);
|
||||
|
||||
ret = dm_gpio_set_value(&uc_priv->reset, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: error at sleep = 1 (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mdelay(10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmc623_get_panel(struct udevice *dev)
|
||||
{
|
||||
struct cmc623_priv *priv = dev_get_priv(dev);
|
||||
int i, ret;
|
||||
|
||||
u32 num = ofnode_graph_get_port_count(dev_ofnode(dev));
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
ofnode remote = ofnode_graph_get_remote_node(dev_ofnode(dev), i, -1);
|
||||
|
||||
ret = uclass_get_device_by_ofnode(UCLASS_PANEL, remote, &priv->panel);
|
||||
if (!ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If this point is reached, no panels were found */
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int cmc623_probe(struct udevice *dev)
|
||||
{
|
||||
struct cmc623_priv *priv = dev_get_priv(dev);
|
||||
int i, ret;
|
||||
|
||||
/* get supplies */
|
||||
for (i = 0; i < ARRAY_SIZE(cmc623_supplies); i++) {
|
||||
ret = device_get_supply_regulator(dev, cmc623_supplies[i], &priv->supplies[i]);
|
||||
if (ret) {
|
||||
log_debug("%s: cannot get %s %d\n", __func__, cmc623_supplies[i], ret);
|
||||
if (ret != -ENOENT)
|
||||
return log_ret(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* get control gpios */
|
||||
ret = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable_gpio, GPIOD_IS_OUT);
|
||||
if (ret) {
|
||||
log_debug("%s: could not get enable-gpios (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_request_by_name(dev, "bypass-gpios", 0, &priv->bypass_gpio, GPIOD_IS_OUT);
|
||||
if (ret) {
|
||||
log_debug("%s: could not get bypass-gpios (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cmc623_hw_init(dev);
|
||||
if (ret) {
|
||||
log_debug("%s: error doing hw init, ret %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cmc623_get_panel(dev);
|
||||
if (ret) {
|
||||
log_debug("%s: panel not found, ret %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
panel_get_display_timing(priv->panel, &priv->timing);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct video_bridge_ops cmc623_ops = {
|
||||
.attach = cmc623_attach,
|
||||
.set_backlight = cmc623_set_backlight,
|
||||
.get_display_timing = cmc623_panel_timings,
|
||||
};
|
||||
|
||||
static const struct udevice_id cmc623_ids[] = {
|
||||
{ .compatible = "samsung,cmc623" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(samsung_cmc623) = {
|
||||
.name = "samsung_cmc623",
|
||||
.id = UCLASS_VIDEO_BRIDGE,
|
||||
.of_match = cmc623_ids,
|
||||
.ops = &cmc623_ops,
|
||||
.bind = dm_scan_fdt_dev,
|
||||
.probe = cmc623_probe,
|
||||
.priv_auto = sizeof(struct cmc623_priv),
|
||||
};
|
124
drivers/video/cmc623_backlight.c
Normal file
124
drivers/video/cmc623_backlight.c
Normal file
@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2025 Ion Agorria <ion@agorria.com>
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT
|
||||
|
||||
#include <backlight.h>
|
||||
#include <dm.h>
|
||||
#include <i2c.h>
|
||||
#include <log.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <power/regulator.h>
|
||||
|
||||
#define CMC623_I2C_REG_SELBANK 0x00
|
||||
#define CMC623_I2C_REG_PWMCTRL 0xb4
|
||||
#define CMC623_I2C_REG_REGMASK 0x28
|
||||
|
||||
#define CMC623_BL_MIN_BRIGHTNESS 0
|
||||
#define CMC623_BL_DEF_BRIGHTNESS 50
|
||||
#define CMC623_BL_MAX_BRIGHTNESS 100
|
||||
|
||||
struct cmc623_backlight_priv {
|
||||
struct gpio_desc enable_gpio;
|
||||
};
|
||||
|
||||
static int cmc623_backlight_enable(struct udevice *dev)
|
||||
{
|
||||
struct cmc623_backlight_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (dm_gpio_is_valid(&priv->enable_gpio))
|
||||
dm_gpio_set_value(&priv->enable_gpio, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmc623_i2c_write(struct udevice *dev, u8 reg, u16 value)
|
||||
{
|
||||
u8 data[2];
|
||||
|
||||
data[0] = (value >> 8) & 0xff;
|
||||
data[1] = value & 0xff;
|
||||
|
||||
return dm_i2c_write(dev->parent, reg, data, 2);
|
||||
}
|
||||
|
||||
static int cmc623_backlight_set_brightness(struct udevice *dev, int percent)
|
||||
{
|
||||
int ret;
|
||||
u16 brightness;
|
||||
|
||||
if (percent == BACKLIGHT_DEFAULT)
|
||||
percent = CMC623_BL_DEF_BRIGHTNESS;
|
||||
|
||||
if (percent < CMC623_BL_MIN_BRIGHTNESS)
|
||||
percent = CMC623_BL_MIN_BRIGHTNESS;
|
||||
|
||||
if (percent > CMC623_BL_MAX_BRIGHTNESS)
|
||||
percent = CMC623_BL_MAX_BRIGHTNESS;
|
||||
|
||||
brightness = 0x4000 | (percent << 4);
|
||||
|
||||
ret = cmc623_i2c_write(dev, CMC623_I2C_REG_SELBANK, 0x0000);
|
||||
if (ret) {
|
||||
log_debug("%s: error at CMC623_I2C_REG_SELBANK (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cmc623_i2c_write(dev, CMC623_I2C_REG_PWMCTRL, brightness);
|
||||
if (ret) {
|
||||
log_debug("%s: error at CMC623_I2C_REG_PWMCTRL (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cmc623_i2c_write(dev, CMC623_I2C_REG_REGMASK, 0x0000);
|
||||
if (ret) {
|
||||
log_debug("%s: error at CMC623_I2C_REG_REGMASK (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmc623_backlight_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct cmc623_backlight_priv *priv = dev_get_priv(dev);
|
||||
|
||||
gpio_request_by_name(dev, "enable-gpios", 0,
|
||||
&priv->enable_gpio, GPIOD_IS_OUT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmc623_backlight_probe(struct udevice *dev)
|
||||
{
|
||||
if (device_get_uclass_id(dev->parent) != UCLASS_VIDEO_BRIDGE)
|
||||
return -EPROTONOSUPPORT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct backlight_ops cmc623_backlight_ops = {
|
||||
.enable = cmc623_backlight_enable,
|
||||
.set_brightness = cmc623_backlight_set_brightness,
|
||||
};
|
||||
|
||||
static const struct udevice_id cmc623_backlight_ids[] = {
|
||||
{ .compatible = "samsung,cmc623-backlight" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(cmc623_backlight) = {
|
||||
.name = "cmc623_backlight",
|
||||
.id = UCLASS_PANEL_BACKLIGHT,
|
||||
.of_match = cmc623_backlight_ids,
|
||||
.of_to_plat = cmc623_backlight_of_to_plat,
|
||||
.probe = cmc623_backlight_probe,
|
||||
.ops = &cmc623_backlight_ops,
|
||||
.priv_auto = sizeof(struct cmc623_backlight_priv),
|
||||
};
|
393
drivers/video/samsung-s6e63m0.c
Normal file
393
drivers/video/samsung-s6e63m0.c
Normal file
@ -0,0 +1,393 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2025 Ion Agorria <ion@agorria.com>
|
||||
*/
|
||||
|
||||
#include <backlight.h>
|
||||
#include <dm.h>
|
||||
#include <panel.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
#include <spi.h>
|
||||
#include <mipi_display.h>
|
||||
#include <linux/delay.h>
|
||||
#include <power/regulator.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#define S6E63M0_DCS_CMD 0
|
||||
#define S6E63M0_DCS_DATA 1
|
||||
|
||||
#define S6E63M0_INFO_FLAG_PGAMMACTL BIT(0)
|
||||
#define S6E63M0_INFO_FLAG_GAMMA_DELTA BIT(1)
|
||||
|
||||
#define S6E63M0_GTCON_FLAG_FLIP_H BIT(0)
|
||||
#define S6E63M0_GTCON_FLAG_FLIP_V BIT(1)
|
||||
|
||||
/* Manufacturer Command Set */
|
||||
#define MCS_PENTILE_1 0xb3
|
||||
#define MCS_GAMMA_DELTA_Y_RED 0xb5
|
||||
#define MCS_GAMMA_DELTA_X_RED 0xb6
|
||||
#define MCS_GAMMA_DELTA_Y_GREEN 0xb7
|
||||
#define MCS_GAMMA_DELTA_X_GREEN 0xb8
|
||||
#define MCS_GAMMA_DELTA_Y_BLUE 0xb9
|
||||
#define MCS_GAMMA_DELTA_X_BLUE 0xba
|
||||
#define MCS_DISCTL 0xf2
|
||||
#define MCS_SRCCTL 0xf6
|
||||
#define MCS_IFCTL 0xf7
|
||||
#define MCS_PANELCTL 0xf8
|
||||
#define MCS_PGAMMACTL 0xfa
|
||||
|
||||
#define MCS_PANELCTL_LEN 14
|
||||
#define MCS_IFCTL_LEN 3
|
||||
#define MCS_PGAMMACTL_LEN 22
|
||||
#define MCS_GAMMA_DELTA_Y_LEN 32
|
||||
#define MCS_GAMMA_DELTA_X_LEN 16
|
||||
|
||||
struct s6e63m0_priv {
|
||||
struct udevice *vdd3;
|
||||
struct udevice *vci;
|
||||
|
||||
struct s6e63m0_info *info;
|
||||
|
||||
struct gpio_desc reset_gpio;
|
||||
|
||||
u8 gtcon;
|
||||
};
|
||||
|
||||
struct s6e63m0_info {
|
||||
const u32 flags;
|
||||
struct display_timing timing;
|
||||
const u8 cmd_mcs_panelctl[MCS_PANELCTL_LEN];
|
||||
const u8 cmd_mcs_pgammactl_1[MCS_PGAMMACTL_LEN];
|
||||
const u8 cmd_mcs_pgammactl_2;
|
||||
const u8 cmd_mcs_gamma_delta_y[MCS_GAMMA_DELTA_Y_LEN];
|
||||
const u8 cmd_mcs_gamma_delta_x[MCS_GAMMA_DELTA_X_LEN];
|
||||
};
|
||||
|
||||
static const struct s6e63m0_info s6e63m0_generic_info = {
|
||||
.flags = S6E63M0_INFO_FLAG_GAMMA_DELTA,
|
||||
.timing = {
|
||||
.pixelclock.typ = 25628,
|
||||
.hactive.typ = 480,
|
||||
.hfront_porch.typ = 16,
|
||||
.hback_porch.typ = 16,
|
||||
.hsync_len.typ = 2,
|
||||
.vactive.typ = 800,
|
||||
.vfront_porch.typ = 28,
|
||||
.vback_porch.typ = 1,
|
||||
.vsync_len.typ = 2,
|
||||
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW,
|
||||
},
|
||||
.cmd_mcs_panelctl = {
|
||||
0x01, /* DOCT */ 0x27, /* CLWEA */
|
||||
0x27, /* CLWEB*/ 0x07, /* CLTE */
|
||||
0x07, /* SHE */ 0x54, /* FLTE */
|
||||
0x9F, /* FLWE */ 0x63, /* SCTE */
|
||||
0x8F, /* SCWE */ 0x1A, /* INTE */
|
||||
0x33, /* INWE */ 0x0D, /* EMPS */
|
||||
0x00, /* E_INTE */ 0x00 /* E_INWE */
|
||||
},
|
||||
.cmd_mcs_pgammactl_1 = {
|
||||
0x00, 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xb6,
|
||||
0xba, 0xa8, 0xac, 0xb1, 0x9d, 0xc1, 0xc1, 0xb7,
|
||||
0x00, 0x9c, 0x00, 0x9f, 0x00, 0xd6
|
||||
},
|
||||
.cmd_mcs_pgammactl_2 = 0x01,
|
||||
.cmd_mcs_gamma_delta_y = {
|
||||
0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17, 0x13,
|
||||
0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b, 0x1a, 0x17,
|
||||
0x2b, 0x26, 0x22, 0x20, 0x3a, 0x34, 0x30, 0x2c,
|
||||
0x29, 0x26, 0x25, 0x23, 0x21, 0x20, 0x1e, 0x1e
|
||||
},
|
||||
.cmd_mcs_gamma_delta_x = {
|
||||
0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44, 0x44,
|
||||
0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66
|
||||
},
|
||||
};
|
||||
|
||||
static const struct s6e63m0_info samsung_bose_panel_info = {
|
||||
.flags = S6E63M0_INFO_FLAG_PGAMMACTL | S6E63M0_INFO_FLAG_GAMMA_DELTA,
|
||||
.timing = {
|
||||
.pixelclock.typ = 24000000,
|
||||
.hactive.typ = 480,
|
||||
.hfront_porch.typ = 16,
|
||||
.hback_porch.typ = 14,
|
||||
.hsync_len.typ = 2,
|
||||
.vactive.typ = 800,
|
||||
.vfront_porch.typ = 28,
|
||||
.vback_porch.typ = 1,
|
||||
.vsync_len.typ = 2,
|
||||
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
|
||||
DISPLAY_FLAGS_DE_LOW | DISPLAY_FLAGS_PIXDATA_NEGEDGE,
|
||||
},
|
||||
.cmd_mcs_panelctl = {
|
||||
0x01, /* DOCT */ 0x27, /* CLWEA */
|
||||
0x27, /* CLWEB*/ 0x07, /* CLTE */
|
||||
0x07, /* SHE */ 0x54, /* FLTE */
|
||||
0x9F, /* FLWE */ 0x63, /* SCTE */
|
||||
0x86, /* SCWE */ 0x1A, /* INTE */
|
||||
0x33, /* INWE */ 0x0D, /* EMPS */
|
||||
0x00, /* E_INTE */ 0x00 /* E_INWE */
|
||||
},
|
||||
.cmd_mcs_pgammactl_1 = {
|
||||
0x02, 0x18, 0x08, 0x24, 0x70, 0x6e, 0x4e, 0xbc,
|
||||
0xc0, 0xaf, 0xb3, 0xb8, 0xa5, 0xc5, 0xc7, 0xbb,
|
||||
0x00, 0xb9, 0x00, 0xb8, 0x00, 0xfc
|
||||
},
|
||||
.cmd_mcs_pgammactl_2 = 0x03,
|
||||
.cmd_mcs_gamma_delta_y = {
|
||||
0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17, 0x13,
|
||||
0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b, 0x1a, 0x17,
|
||||
0x2b, 0x26, 0x22, 0x20, 0x3a, 0x34, 0x30, 0x2c,
|
||||
0x29, 0x26, 0x25, 0x23, 0x21, 0x20, 0x1e, 0x1e
|
||||
},
|
||||
.cmd_mcs_gamma_delta_x = {
|
||||
0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44, 0x44,
|
||||
0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66
|
||||
},
|
||||
};
|
||||
|
||||
static int s6e63m0_dcs_write(struct udevice *dev, u8 cmd, const u8 *seq, size_t len)
|
||||
{
|
||||
int ret;
|
||||
u8 data[2];
|
||||
int i;
|
||||
|
||||
data[0] = S6E63M0_DCS_CMD;
|
||||
data[1] = cmd;
|
||||
|
||||
ret = dm_spi_xfer(dev, 9, &data, NULL, SPI_XFER_ONCE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
data[0] = S6E63M0_DCS_DATA;
|
||||
data[1] = seq[i];
|
||||
|
||||
ret = dm_spi_xfer(dev, 9, &data, NULL, SPI_XFER_ONCE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define s6e63m0_dcs_write_seq_static(dev, cmd, seq ...) ({ \
|
||||
static const u8 d[] = { seq }; \
|
||||
ret = s6e63m0_dcs_write(dev, cmd, d, ARRAY_SIZE(d)); \
|
||||
if (ret) \
|
||||
return ret; \
|
||||
})
|
||||
|
||||
static int s6e63m0_enable_backlight(struct udevice *dev)
|
||||
{
|
||||
struct s6e63m0_priv *priv = dev_get_priv(dev);
|
||||
struct s6e63m0_info *info = priv->info;
|
||||
u8 cmd_mcs_ifctl[MCS_IFCTL_LEN];
|
||||
int ret;
|
||||
|
||||
ret = s6e63m0_dcs_write(dev, MCS_PANELCTL, info->cmd_mcs_panelctl, MCS_PANELCTL_LEN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
s6e63m0_dcs_write_seq_static(dev, MCS_DISCTL,
|
||||
0x02, /* Number of Line */
|
||||
0x03, /* VBP */
|
||||
0x1c, /* VFP */
|
||||
0x10, /* HBP */
|
||||
0x10); /* HFP */
|
||||
|
||||
cmd_mcs_ifctl[0] = priv->gtcon; /* GTCON */
|
||||
cmd_mcs_ifctl[1] = 0x00; /* Display Mode */
|
||||
cmd_mcs_ifctl[2] = 0x00; /* Vsync/Hsync, DOCCLK, RGB mode */
|
||||
ret = s6e63m0_dcs_write(dev, MCS_IFCTL, cmd_mcs_ifctl, MCS_IFCTL_LEN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (info->flags & S6E63M0_INFO_FLAG_PGAMMACTL) {
|
||||
ret = s6e63m0_dcs_write(dev, MCS_PGAMMACTL, info->cmd_mcs_pgammactl_1,
|
||||
MCS_PGAMMACTL_LEN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
s6e63m0_dcs_write(dev, MCS_PGAMMACTL, &info->cmd_mcs_pgammactl_2, 1);
|
||||
}
|
||||
|
||||
s6e63m0_dcs_write_seq_static(dev, MCS_SRCCTL, 0x00, 0x8e, 0x07);
|
||||
s6e63m0_dcs_write_seq_static(dev, MCS_PENTILE_1, 0x6c);
|
||||
|
||||
if (info->flags & S6E63M0_INFO_FLAG_GAMMA_DELTA) {
|
||||
ret = s6e63m0_dcs_write(dev, MCS_GAMMA_DELTA_Y_RED, info->cmd_mcs_gamma_delta_y,
|
||||
MCS_GAMMA_DELTA_Y_LEN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = s6e63m0_dcs_write(dev, MCS_GAMMA_DELTA_X_RED, info->cmd_mcs_gamma_delta_x,
|
||||
MCS_GAMMA_DELTA_X_LEN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = s6e63m0_dcs_write(dev, MCS_GAMMA_DELTA_Y_GREEN, info->cmd_mcs_gamma_delta_y,
|
||||
MCS_GAMMA_DELTA_Y_LEN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = s6e63m0_dcs_write(dev, MCS_GAMMA_DELTA_X_GREEN, info->cmd_mcs_gamma_delta_x,
|
||||
MCS_GAMMA_DELTA_X_LEN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = s6e63m0_dcs_write(dev, MCS_GAMMA_DELTA_Y_BLUE, info->cmd_mcs_gamma_delta_y,
|
||||
MCS_GAMMA_DELTA_Y_LEN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = s6e63m0_dcs_write(dev, MCS_GAMMA_DELTA_X_BLUE, info->cmd_mcs_gamma_delta_x,
|
||||
MCS_GAMMA_DELTA_X_LEN);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
s6e63m0_dcs_write_seq_static(dev, MIPI_DCS_EXIT_SLEEP_MODE);
|
||||
s6e63m0_dcs_write_seq_static(dev, MIPI_DCS_SET_DISPLAY_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s6e63m0_set_backlight(struct udevice *dev, int percent)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s6e63m0_get_display_timing(struct udevice *dev, struct display_timing *timing)
|
||||
{
|
||||
struct s6e63m0_priv *priv = dev_get_priv(dev);
|
||||
|
||||
memcpy(timing, &priv->info->timing, sizeof(*timing));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s6e63m0_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct s6e63m0_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = device_get_supply_regulator(dev, "vdd3-supply", &priv->vdd3);
|
||||
if (ret) {
|
||||
log_debug("%s: cannot get vdd3-supply: ret = %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_get_supply_regulator(dev, "vci-supply", &priv->vci);
|
||||
if (ret) {
|
||||
log_debug("%s: cannot get vci-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 decode reset-gpios (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dev_read_bool(dev, "flip-horizontal"))
|
||||
priv->gtcon |= S6E63M0_GTCON_FLAG_FLIP_H;
|
||||
|
||||
if (dev_read_bool(dev, "flip-vertical"))
|
||||
priv->gtcon |= S6E63M0_GTCON_FLAG_FLIP_V;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s6e63m0_hw_init(struct udevice *dev)
|
||||
{
|
||||
struct s6e63m0_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = dm_gpio_set_value(&priv->reset_gpio, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: error entering reset (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_set_enable_if_allowed(priv->vdd3, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: enabling vdd3-supply failed (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mdelay(1);
|
||||
|
||||
ret = regulator_set_enable_if_allowed(priv->vci, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: enabling vci-supply failed (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mdelay(26);
|
||||
|
||||
ret = dm_gpio_set_value(&priv->reset_gpio, 0);
|
||||
if (ret) {
|
||||
log_debug("%s: error exiting reset (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mdelay(10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s6e63m0_probe(struct udevice *dev)
|
||||
{
|
||||
struct s6e63m0_priv *priv = dev_get_priv(dev);
|
||||
struct spi_slave *slave = dev_get_parent_priv(dev);
|
||||
int ret;
|
||||
|
||||
if (device_get_uclass_id(dev->parent) != UCLASS_SPI)
|
||||
return -EPROTONOSUPPORT;
|
||||
|
||||
ret = spi_claim_bus(slave);
|
||||
if (ret) {
|
||||
log_err("SPI bus allocation failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->info = (struct s6e63m0_info *)dev_get_driver_data(dev);
|
||||
|
||||
return s6e63m0_hw_init(dev);
|
||||
}
|
||||
|
||||
static const struct panel_ops s6e63m0_ops = {
|
||||
.enable_backlight = s6e63m0_enable_backlight,
|
||||
.set_backlight = s6e63m0_set_backlight,
|
||||
.get_display_timing = s6e63m0_get_display_timing,
|
||||
};
|
||||
|
||||
static const struct udevice_id s6e63m0_ids[] = {
|
||||
{
|
||||
.compatible = "samsung,s6e63m0",
|
||||
.data = (ulong)&s6e63m0_generic_info
|
||||
},
|
||||
{
|
||||
.compatible = "samsung,bose-panel",
|
||||
.data = (ulong)&samsung_bose_panel_info
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(samsung_s6e63m0) = {
|
||||
.name = "samsung_s6e63m0",
|
||||
.id = UCLASS_PANEL,
|
||||
.of_match = s6e63m0_ids,
|
||||
.ops = &s6e63m0_ops,
|
||||
.of_to_plat = s6e63m0_of_to_plat,
|
||||
.probe = s6e63m0_probe,
|
||||
.priv_auto = sizeof(struct s6e63m0_priv),
|
||||
};
|
210
drivers/video/sony-l4f00430t01.c
Normal file
210
drivers/video/sony-l4f00430t01.c
Normal file
@ -0,0 +1,210 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2025 Ion Agorria <ion@agorria.com>
|
||||
*/
|
||||
|
||||
#include <backlight.h>
|
||||
#include <dm.h>
|
||||
#include <panel.h>
|
||||
#include <log.h>
|
||||
#include <spi.h>
|
||||
#include <mipi_display.h>
|
||||
#include <linux/delay.h>
|
||||
#include <power/regulator.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#define SONY_L4F00430T01_DCS_CMD 0
|
||||
#define SONY_L4F00430T01_DCS_DATA 1
|
||||
|
||||
struct sony_l4f00430t01_priv {
|
||||
struct udevice *vdd1v8;
|
||||
struct udevice *vdd3v0;
|
||||
|
||||
struct udevice *backlight;
|
||||
|
||||
struct gpio_desc reset_gpio;
|
||||
};
|
||||
|
||||
static struct display_timing default_timing = {
|
||||
.pixelclock.typ = 24000000,
|
||||
.hactive.typ = 480,
|
||||
.hfront_porch.typ = 10,
|
||||
.hback_porch.typ = 20,
|
||||
.hsync_len.typ = 10,
|
||||
.vactive.typ = 800,
|
||||
.vfront_porch.typ = 3,
|
||||
.vback_porch.typ = 4,
|
||||
.vsync_len.typ = 2,
|
||||
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
|
||||
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_NEGEDGE,
|
||||
};
|
||||
|
||||
static int sony_l4f00430t01_write(struct udevice *dev, u8 cmd, const u8 *seq, int len)
|
||||
{
|
||||
u8 data[2];
|
||||
int i, ret;
|
||||
|
||||
data[0] = SONY_L4F00430T01_DCS_CMD;
|
||||
data[1] = cmd;
|
||||
|
||||
ret = dm_spi_xfer(dev, 9, &data, NULL, SPI_XFER_ONCE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
data[0] = SONY_L4F00430T01_DCS_DATA;
|
||||
data[1] = seq[i];
|
||||
|
||||
ret = dm_spi_xfer(dev, 9, &data, NULL, SPI_XFER_ONCE);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define sony_l4f00430t01_write_seq(dev, cmd, seq...) do { \
|
||||
static const u8 b[] = { seq }; \
|
||||
sony_l4f00430t01_write(dev, cmd, b, ARRAY_SIZE(b)); \
|
||||
} while (0)
|
||||
|
||||
static int sony_l4f00430t01_enable_backlight(struct udevice *dev)
|
||||
{
|
||||
sony_l4f00430t01_write_seq(dev, MIPI_DCS_SET_ADDRESS_MODE, 0xd4);
|
||||
mdelay(25);
|
||||
|
||||
sony_l4f00430t01_write_seq(dev, MIPI_DCS_EXIT_SLEEP_MODE);
|
||||
mdelay(150);
|
||||
|
||||
sony_l4f00430t01_write_seq(dev, MIPI_DCS_SET_DISPLAY_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sony_l4f00430t01_set_backlight(struct udevice *dev, int percent)
|
||||
{
|
||||
struct sony_l4f00430t01_priv *priv = dev_get_priv(dev);
|
||||
int 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 = backlight_enable(priv->backlight);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return backlight_set_brightness(priv->backlight, percent);
|
||||
}
|
||||
|
||||
static int sony_l4f00430t01_get_display_timing(struct udevice *dev,
|
||||
struct display_timing *timing)
|
||||
{
|
||||
memcpy(timing, &default_timing, sizeof(*timing));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sony_l4f00430t01_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct sony_l4f00430t01_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = device_get_supply_regulator(dev, "vdd1v8-supply", &priv->vdd1v8);
|
||||
if (ret) {
|
||||
log_debug("%s: cannot get vdd1v8-supply: ret = %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_get_supply_regulator(dev, "vdd3v0-supply", &priv->vdd3v0);
|
||||
if (ret) {
|
||||
log_debug("%s: cannot get vdd3v0-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 decode reset-gpios (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sony_l4f00430t01_hw_init(struct udevice *dev)
|
||||
{
|
||||
struct sony_l4f00430t01_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = dm_gpio_set_value(&priv->reset_gpio, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: error entering reset (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_set_enable_if_allowed(priv->vdd1v8, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: enabling vdd1v8-supply failed (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_set_enable_if_allowed(priv->vdd3v0, 1);
|
||||
if (ret) {
|
||||
log_debug("%s: enabling vdd3v0-supply failed (%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
mdelay(15);
|
||||
|
||||
ret = dm_gpio_set_value(&priv->reset_gpio, 0);
|
||||
if (ret) {
|
||||
log_debug("%s: error exiting reset (%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
mdelay(100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sony_l4f00430t01_probe(struct udevice *dev)
|
||||
{
|
||||
struct spi_slave *slave = dev_get_parent_priv(dev);
|
||||
int ret;
|
||||
|
||||
ret = spi_claim_bus(slave);
|
||||
if (ret) {
|
||||
log_err("SPI bus allocation failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return sony_l4f00430t01_hw_init(dev);
|
||||
}
|
||||
|
||||
static const struct panel_ops sony_l4f00430t01_ops = {
|
||||
.enable_backlight = sony_l4f00430t01_enable_backlight,
|
||||
.set_backlight = sony_l4f00430t01_set_backlight,
|
||||
.get_display_timing = sony_l4f00430t01_get_display_timing,
|
||||
};
|
||||
|
||||
static const struct udevice_id sony_l4f00430t01_ids[] = {
|
||||
{ .compatible = "sony,l4f00430t01" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(sony_l4f00430t01) = {
|
||||
.name = "sony_l4f00430t01",
|
||||
.id = UCLASS_PANEL,
|
||||
.of_match = sony_l4f00430t01_ids,
|
||||
.ops = &sony_l4f00430t01_ops,
|
||||
.of_to_plat = sony_l4f00430t01_of_to_plat,
|
||||
.probe = sony_l4f00430t01_probe,
|
||||
.priv_auto = sizeof(struct sony_l4f00430t01_priv),
|
||||
};
|
@ -238,8 +238,24 @@ static void rgb_enable(struct tegra_lcd_priv *priv)
|
||||
else
|
||||
value &= ~LVS_OUTPUT_POLARITY_LOW;
|
||||
|
||||
/* configure pixel data signal polarity */
|
||||
if (dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
|
||||
value &= ~LSC0_OUTPUT_POLARITY_LOW;
|
||||
else
|
||||
value |= LSC0_OUTPUT_POLARITY_LOW;
|
||||
|
||||
writel(value, &com->pin_output_polarity[1]);
|
||||
|
||||
/* configure data enable signal polarity */
|
||||
value = readl(&com->pin_output_polarity[3]);
|
||||
|
||||
if (dt->flags & DISPLAY_FLAGS_DE_LOW)
|
||||
value |= LSPI_OUTPUT_POLARITY_LOW;
|
||||
else
|
||||
value &= ~LSPI_OUTPUT_POLARITY_LOW;
|
||||
|
||||
writel(value, &com->pin_output_polarity[3]);
|
||||
|
||||
for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++)
|
||||
writel(rgb_sel_tab[i], &com->pin_output_sel[i]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user