Merge git://git.denx.de/u-boot-dm

This commit is contained in:
Tom Rini 2015-08-06 19:56:03 -04:00
commit ae27120c31
124 changed files with 5743 additions and 2291 deletions

View File

@ -51,6 +51,12 @@ config TARGET_SNOW
select OF_CONTROL
select SPL_DISABLE_OF_CONTROL
config TARGET_SPRING
bool "Spring board"
select SUPPORT_SPL
select OF_CONTROL
select SPL_DISABLE_OF_CONTROL
config TARGET_SMDK5420
bool "SMDK5420 board"
select SUPPORT_SPL

View File

@ -25,6 +25,7 @@
#include <common.h>
#include <config.h>
#include <debug_uart.h>
#include <asm/arch/cpu.h>
#include <asm/arch/dmc.h>
#include <asm/arch/power.h>
@ -216,6 +217,10 @@ int do_lowlevel_init(void)
if (actions & DO_CLOCKS) {
system_clock_init();
#ifdef CONFIG_DEBUG_UART
exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);
debug_uart_init();
#endif
mem_ctrl_init(actions & DO_MEM_RESET);
tzpc_init();
}

View File

@ -496,6 +496,16 @@ static int exynos5_pinmux_config(int peripheral, int flags)
case PERIPH_ID_SPI4:
exynos5_spi_config(peripheral);
break;
case PERIPH_ID_DPHPD:
/* Set Hotplug detect for DP */
gpio_cfg_pin(EXYNOS5_GPIO_X07, S5P_GPIO_FUNC(0x3));
/*
* Hotplug detect should have an external pullup; disable the
* internal pulldown so they don't fight.
*/
gpio_set_pull(EXYNOS5_GPIO_X07, S5P_GPIO_PULL_NONE);
break;
default:
debug("%s: invalid peripheral %d", __func__, peripheral);
return -1;

View File

@ -30,11 +30,8 @@ u32 get_device_type(void)
#ifdef CONFIG_DISPLAY_CPUINFO
int print_cpuinfo(void)
{
char buf[32];
printf("CPU:\t%s%X@%sMHz\n",
s5p_get_cpu_name(), s5p_cpu_id,
strmhz(buf, get_arm_clk()));
printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
print_freq(get_arm_clk(), "\n");
return 0;
}

View File

@ -9,6 +9,7 @@ dtb-$(CONFIG_EXYNOS4) += exynos4210-origen.dtb \
dtb-$(CONFIG_EXYNOS5) += exynos5250-arndale.dtb \
exynos5250-snow.dtb \
exynos5250-spring.dtb \
exynos5250-smdk5250.dtb \
exynos5420-smdk5420.dtb \
exynos5420-peach-pit.dtb \

View File

@ -42,103 +42,103 @@
#clock-cells = <1>;
voltage-regulators {
ldo1_reg: ldo1 {
ldo1_reg: LDO1 {
regulator-name = "VDD_ALIVE_1.0V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
ldo2_reg: ldo2 {
ldo2_reg: LDO2 {
regulator-name = "VDDQ_VM1M2_1.2V";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
ldo3_reg: ldo3 {
ldo3_reg: LDO3 {
regulator-name = "VCC_1.8V_AP";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo4_reg: ldo4 {
ldo4_reg: LDO4 {
regulator-name = "VDDQ_MMC2_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
};
ldo5_reg: ldo5 {
ldo5_reg: LDO5 {
regulator-name = "VDDQ_MMC0/1/3_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo6_reg: ldo6 {
ldo6_reg: LDO6 {
regulator-name = "VMPLL_1.0V";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
};
ldo7_reg: ldo7 {
ldo7_reg: LDO7 {
regulator-name = "VPLL_1.1V";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
};
ldo8_reg: ldo8 {
ldo8_reg: LDO8 {
regulator-name = "VDD_MIPI/HDMI_1.0V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
ldo10_reg: ldo10 {
ldo10_reg: LDO10 {
regulator-name = "VDD_MIPI/HDMI_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo11_reg: ldo11 {
ldo11_reg: LDO11 {
regulator-name = "VDD_ABB1_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo12_reg: ldo12 {
ldo12_reg: LDO12 {
regulator-name = "VDD_UOTG_3.0V";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
ldo13_reg: ldo13 {
ldo13_reg: LDO13 {
regulator-name = "VDD_C2C_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo14_reg: ldo14 {
ldo14_reg: LDO14 {
regulator-name = "VDD_ABB02_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo15_reg: ldo15 {
ldo15_reg: LDO15 {
regulator-name = "VDD_HSIC/OTG_1.0V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
ldo16_reg: ldo16 {
ldo16_reg: LDO16 {
regulator-name = "VDD_HSIC_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo17_reg: ldo17 {
ldo17_reg: LDO17 {
regulator-name = "VDDQ_CAM_1.2V";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
ldo20_reg: ldo20 {
ldo20_reg: LDO20 {
regulator-name = "VDDQ_EMMC_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@ -146,7 +146,7 @@
regulator-boot-on;
};
ldo21_reg: ldo21 {
ldo21_reg: LDO21 {
regulator-name = "TFLASH_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
@ -154,7 +154,7 @@
regulator-boot-on;
};
ldo22_reg: ldo22 {
ldo22_reg: LDO22 {
regulator-name = "VDDQ_EMMC_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
@ -162,56 +162,56 @@
regulator-boot-on;
};
ldo25_reg: ldo25 {
ldo25_reg: LDO25 {
regulator-compatible = "LDO25";
regulator-name = "VDDQ_LCD_3.0V";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
buck1_reg: buck1 {
buck1_reg: BUCK1 {
regulator-name = "VDD_MIF_1.0V";
regulator-min-microvolt = <8500000>;
regulator-max-microvolt = <1100000>;
};
buck2_reg: buck2 {
buck2_reg: BUCK2 {
regulator-name = "VDD_ARM_1.0V";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1500000>;
};
buck3_reg: buck3 {
buck3_reg: BUCK3 {
regulator-name = "VDD_INT_1.1V";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1150000>;
};
buck4_reg: buck4 {
buck4_reg: BUCK4 {
regulator-name = "VDD_G3D_1.0V";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1150000>;
};
buck5_reg: buck5 {
buck5_reg: BUCK5 {
regulator-name = "VDDQ_AP_1.2V";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
buck6_reg: buck6 {
buck6_reg: BUCK6 {
regulator-name = "VCC_INL1/7_1.35V";
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
};
buck7_reg: buck7 {
buck7_reg: BUCK7 {
regulator-name = "VCC_INL2/3/5_2.0V";
regulator-min-microvolt = <2000000>;
regulator-max-microvolt = <2000000>;
};
buck8_reg: buck8 {
buck8_reg: BUCK8 {
regulator-name = "VCC_P3V3_2.85V";
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <3300000>;

View File

@ -47,7 +47,7 @@
#clock-cells = <1>;
voltage-regulators {
ldo1_reg: ldo1 {
ldo1_reg: LDO1 {
regulator-compatible = "LDO1";
regulator-name = "VALIVE_1.0V_AP";
regulator-min-microvolt = <1000000>;
@ -56,7 +56,7 @@
regulator-mem-on;
};
ldo2_reg: ldo2 {
ldo2_reg: LDO2 {
regulator-compatible = "LDO2";
regulator-name = "VM1M2_1.2V_AP";
regulator-min-microvolt = <1200000>;
@ -65,7 +65,7 @@
regulator-mem-on;
};
ldo3_reg: ldo3 {
ldo3_reg: LDO3 {
regulator-compatible = "LDO3";
regulator-name = "VCC_1.8V_AP";
regulator-min-microvolt = <1800000>;
@ -74,7 +74,7 @@
regulator-mem-on;
};
ldo4_reg: ldo4 {
ldo4_reg: LDO4 {
regulator-compatible = "LDO4";
regulator-name = "VCC_2.8V_AP";
regulator-min-microvolt = <2800000>;
@ -83,7 +83,7 @@
regulator-mem-on;
};
ldo5_reg: ldo5 {
ldo5_reg: LDO5 {
regulator-compatible = "LDO5";
regulator-name = "VCC_1.8V_IO";
regulator-min-microvolt = <1800000>;
@ -92,7 +92,7 @@
regulator-mem-on;
};
ldo6_reg: ldo6 {
ldo6_reg: LDO6 {
regulator-compatible = "LDO6";
regulator-name = "VMPLL_1.0V_AP";
regulator-min-microvolt = <1000000>;
@ -101,7 +101,7 @@
regulator-mem-on;
};
ldo7_reg: ldo7 {
ldo7_reg: LDO7 {
regulator-compatible = "LDO7";
regulator-name = "VPLL_1.0V_AP";
regulator-min-microvolt = <1000000>;
@ -110,7 +110,7 @@
regulator-mem-on;
};
ldo8_reg: ldo8 {
ldo8_reg: LDO8 {
regulator-compatible = "LDO8";
regulator-name = "VMIPI_1.0V";
regulator-min-microvolt = <1000000>;
@ -118,7 +118,7 @@
regulator-mem-off;
};
ldo9_reg: ldo9 {
ldo9_reg: LDO9 {
regulator-compatible = "LDO9";
regulator-name = "CAM_ISP_MIPI_1.2V";
regulator-min-microvolt = <1200000>;
@ -126,7 +126,7 @@
regulator-mem-idle;
};
ldo10_reg: ldo10 {
ldo10_reg: LDO10 {
regulator-compatible = "LDO10";
regulator-name = "VMIPI_1.8V";
regulator-min-microvolt = <1800000>;
@ -134,7 +134,7 @@
regulator-mem-off;
};
ldo11_reg: ldo11 {
ldo11_reg: LDO11 {
regulator-compatible = "LDO11";
regulator-name = "VABB1_1.95V";
regulator-min-microvolt = <1950000>;
@ -143,7 +143,7 @@
regulator-mem-off;
};
ldo12_reg: ldo12 {
ldo12_reg: LDO12 {
regulator-compatible = "LDO12";
regulator-name = "VUOTG_3.0V";
regulator-min-microvolt = <3000000>;
@ -151,7 +151,7 @@
regulator-mem-off;
};
ldo13_reg: ldo13 {
ldo13_reg: LDO13 {
regulator-compatible = "LDO13";
regulator-name = "NFC_AVDD_1.8V";
regulator-min-microvolt = <1800000>;
@ -159,7 +159,7 @@
regulator-mem-idle;
};
ldo14_reg: ldo14 {
ldo14_reg: LDO14 {
regulator-compatible = "LDO14";
regulator-name = "VABB2_1.95V";
regulator-min-microvolt = <1950000>;
@ -168,7 +168,7 @@
regulator-mem-off;
};
ldo15_reg: ldo15 {
ldo15_reg: LDO15 {
regulator-compatible = "LDO15";
regulator-name = "VHSIC_1.0V";
regulator-min-microvolt = <1000000>;
@ -176,7 +176,7 @@
regulator-mem-off;
};
ldo16_reg: ldo16 {
ldo16_reg: LDO16 {
regulator-compatible = "LDO16";
regulator-name = "VHSIC_1.8V";
regulator-min-microvolt = <1800000>;
@ -184,7 +184,7 @@
regulator-mem-off;
};
ldo17_reg: ldo17 {
ldo17_reg: LDO17 {
regulator-compatible = "LDO17";
regulator-name = "CAM_SENSOR_CORE_1.2V";
regulator-min-microvolt = <1200000>;
@ -192,7 +192,7 @@
regulator-mem-idle;
};
ldo18_reg: ldo18 {
ldo18_reg: LDO18 {
regulator-compatible = "LDO18";
regulator-name = "CAM_ISP_SEN_IO_1.8V";
regulator-min-microvolt = <1800000>;
@ -200,7 +200,7 @@
regulator-mem-idle;
};
ldo19_reg: ldo19 {
ldo19_reg: LDO19 {
regulator-compatible = "LDO19";
regulator-name = "VT_CAM_1.8V";
regulator-min-microvolt = <1800000>;
@ -208,7 +208,7 @@
regulator-mem-idle;
};
ldo20_reg: ldo20 {
ldo20_reg: LDO20 {
regulator-compatible = "LDO20";
regulator-name = "VDDQ_PRE_1.8V";
regulator-min-microvolt = <1800000>;
@ -216,7 +216,7 @@
regulator-mem-idle;
};
ldo21_reg: ldo21 {
ldo21_reg: LDO21 {
regulator-compatible = "LDO21";
regulator-name = "VTF_2.8V";
regulator-min-microvolt = <2800000>;
@ -224,7 +224,7 @@
regulator-mem-idle;
};
ldo22_reg: ldo22 {
ldo22_reg: LDO22 {
regulator-compatible = "LDO22";
regulator-name = "VMEM_VDD_2.8V";
regulator-min-microvolt = <2800000>;
@ -233,7 +233,7 @@
regulator-mem-off;
};
ldo23_reg: ldo23 {
ldo23_reg: LDO23 {
regulator-compatible = "LDO23";
regulator-name = "TSP_AVDD_3.3V";
regulator-min-microvolt = <3300000>;
@ -241,7 +241,7 @@
regulator-mem-idle;
};
ldo24_reg: ldo24 {
ldo24_reg: LDO24 {
regulator-compatible = "LDO24";
regulator-name = "TSP_VDD_1.8V";
regulator-min-microvolt = <1800000>;
@ -249,7 +249,7 @@
regulator-mem-idle;
};
ldo25_reg: ldo25 {
ldo25_reg: LDO25 {
regulator-compatible = "LDO25";
regulator-name = "LCD_VCC_3.3V";
regulator-min-microvolt = <2800000>;
@ -257,7 +257,7 @@
regulator-mem-idle;
};
ldo26_reg: ldo26 {
ldo26_reg: LDO26 {
regulator-compatible = "LDO26";
regulator-name = "MOTOR_VCC_3.0V";
regulator-min-microvolt = <3000000>;
@ -265,7 +265,7 @@
regulator-mem-idle;
};
buck1_reg: buck1 {
buck1_reg: BUCK1 {
regulator-compatible = "BUCK1";
regulator-name = "vdd_mif";
regulator-min-microvolt = <850000>;
@ -275,7 +275,7 @@
regulator-mem-off;
};
buck2_reg: buck2 {
buck2_reg: BUCK2 {
regulator-compatible = "BUCK2";
regulator-name = "vdd_arm";
regulator-min-microvolt = <850000>;
@ -285,7 +285,7 @@
regulator-mem-off;
};
buck3_reg: buck3 {
buck3_reg: BUCK3 {
regulator-compatible = "BUCK3";
regulator-name = "vdd_int";
regulator-min-microvolt = <850000>;
@ -295,7 +295,7 @@
regulator-mem-off;
};
buck4_reg: buck4 {
buck4_reg: BUCK4 {
regulator-compatible = "BUCK4";
regulator-name = "vdd_g3d";
regulator-min-microvolt = <850000>;
@ -304,7 +304,7 @@
regulator-mem-off;
};
buck5_reg: buck5 {
buck5_reg: BUCK5 {
regulator-compatible = "BUCK5";
regulator-name = "VMEM_1.2V_AP";
regulator-min-microvolt = <1200000>;
@ -312,7 +312,7 @@
regulator-always-on;
};
buck6_reg: buck6 {
buck6_reg: BUCK6 {
regulator-compatible = "BUCK6";
regulator-name = "VCC_SUB_1.35V";
regulator-min-microvolt = <1350000>;
@ -320,7 +320,7 @@
regulator-always-on;
};
buck7_reg: buck7 {
buck7_reg: BUCK7 {
regulator-compatible = "BUCK7";
regulator-name = "VCC_SUB_2.0V";
regulator-min-microvolt = <2000000>;
@ -328,7 +328,7 @@
regulator-always-on;
};
buck8_reg: buck8 {
buck8_reg: BUCK8 {
regulator-compatible = "BUCK8";
regulator-name = "VMEM_VDDF_3.0V";
regulator-min-microvolt = <2850000>;
@ -337,7 +337,7 @@
regulator-mem-off;
};
buck9_reg: buck9 {
buck9_reg: BUCK9 {
regulator-compatible = "BUCK9";
regulator-name = "CAM_ISP_CORE_1.2V";
regulator-min-microvolt = <1000000>;

View File

@ -72,39 +72,39 @@
interrupts = <1 9 0xf04>;
};
i2c@12c60000 {
#address-cells = <1>;
#size-cells = <0>;
i2c_0: i2c@12C60000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12C60000 0x100>;
interrupts = <0 56 0>;
};
i2c@12c70000 {
#address-cells = <1>;
#size-cells = <0>;
};
i2c_1: i2c@12C70000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12C70000 0x100>;
interrupts = <0 57 0>;
};
i2c@12c80000 {
#address-cells = <1>;
#size-cells = <0>;
};
i2c_2: i2c@12C80000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12C80000 0x100>;
interrupts = <0 58 0>;
};
i2c@12c90000 {
#address-cells = <1>;
#size-cells = <0>;
};
i2c_3: i2c@12C90000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12C90000 0x100>;
interrupts = <0 59 0>;
#address-cells = <1>;
#size-cells = <0>;
};
spi@12d20000 {
spi_0: spi@12d20000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";
@ -112,7 +112,7 @@
interrupts = <0 68 0>;
};
spi@12d30000 {
spi_1: spi@12d30000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";
@ -120,7 +120,7 @@
interrupts = <0 69 0>;
};
spi@12d40000 {
spi_2: spi@12d40000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";
@ -129,7 +129,7 @@
interrupts = <0 70 0>;
};
spi@131a0000 {
spi_3: spi@131a0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";
@ -137,7 +137,7 @@
interrupts = <0 129 0>;
};
spi@131b0000 {
spi_4: spi@131b0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos-spi";

View File

@ -15,14 +15,14 @@
compatible = "samsung,arndale", "samsung,exynos5250";
aliases {
i2c0 = "/i2c@12c60000";
i2c1 = "/i2c@12c70000";
i2c2 = "/i2c@12c80000";
i2c3 = "/i2c@12c90000";
i2c4 = "/i2c@12ca0000";
i2c5 = "/i2c@12cb0000";
i2c6 = "/i2c@12cc0000";
i2c7 = "/i2c@12cd0000";
i2c0 = "/i2c@12C60000";
i2c1 = "/i2c@12C70000";
i2c2 = "/i2c@12C80000";
i2c3 = "/i2c@12C90000";
i2c4 = "/i2c@12CA0000";
i2c5 = "/i2c@12CB0000";
i2c6 = "/i2c@12CC0000";
i2c7 = "/i2c@12CD0000";
serial0 = "/serial@12C20000";
console = "/serial@12C20000";
};

View File

@ -11,20 +11,21 @@
/dts-v1/;
#include "exynos5250.dtsi"
#include <dt-bindings/interrupt-controller/irq.h>
/ {
model = "SAMSUNG SMDK5250 board based on EXYNOS5250";
compatible = "samsung,smdk5250", "samsung,exynos5250";
aliases {
i2c0 = "/i2c@12c60000";
i2c1 = "/i2c@12c70000";
i2c2 = "/i2c@12c80000";
i2c3 = "/i2c@12c90000";
i2c4 = "/i2c@12ca0000";
i2c5 = "/i2c@12cb0000";
i2c6 = "/i2c@12cc0000";
i2c7 = "/i2c@12cd0000";
i2c0 = "/i2c@12C60000";
i2c1 = "/i2c@12C70000";
i2c2 = "/i2c@12C80000";
i2c3 = "/i2c@12C90000";
i2c4 = "/i2c@12CA0000";
i2c5 = "/i2c@12CB0000";
i2c6 = "/i2c@12CC0000";
i2c7 = "/i2c@12CD0000";
spi0 = "/spi@12d20000";
spi1 = "/spi@12d30000";
spi2 = "/spi@12d40000";
@ -58,14 +59,14 @@
status = "disabled";
};
i2c@12c70000 {
i2c@12C70000 {
soundcodec@1a {
reg = <0x1a>;
compatible = "wolfson,wm8994-codec";
};
};
i2c@12c60000 {
i2c@12C60000 {
pmic@9 {
reg = <0x9>;
compatible = "maxim,max77686";
@ -149,3 +150,153 @@
samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
};
};
&i2c_0 {
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <20000>;
max77686@09 {
compatible = "maxim,max77686";
reg = <0x09>;
interrupt-parent = <&gpx3>;
interrupts = <2 IRQ_TYPE_NONE>;
voltage-regulators {
ldo1_reg: LDO1 {
regulator-name = "P1.0V_LDO_OUT1";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-always-on;
};
ldo2_reg: LDO2 {
regulator-name = "P1.2V_LDO_OUT2";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
};
ldo3_reg: LDO3 {
regulator-name = "P1.8V_LDO_OUT3";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
ldo4_reg: LDO4 {
regulator-name = "P2.8V_LDO_OUT4";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
};
ldo5_reg: LDO5 {
regulator-name = "P1.8V_LDO_OUT5";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo6_reg: LDO6 {
regulator-name = "P1.1V_LDO_OUT6";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
regulator-always-on;
};
ldo7_reg: LDO7 {
regulator-name = "P1.1V_LDO_OUT7";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
regulator-always-on;
};
ldo8_reg: LDO8 {
regulator-name = "P1.0V_LDO_OUT8";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
ldo10_reg: LDO10 {
regulator-name = "P1.8V_LDO_OUT10";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo11_reg: LDO11 {
regulator-name = "P1.8V_LDO_OUT11";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo12_reg: LDO12 {
regulator-name = "P3.0V_LDO_OUT12";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
ldo13_reg: LDO13 {
regulator-name = "P1.8V_LDO_OUT13";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo14_reg: LDO14 {
regulator-name = "P1.8V_LDO_OUT14";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo15_reg: LDO15 {
regulator-name = "P1.0V_LDO_OUT15";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
ldo16_reg: LDO16 {
regulator-name = "P1.8V_LDO_OUT16";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
buck1_reg: BUCK1 {
regulator-name = "vdd_mif";
regulator-min-microvolt = <950000>;
regulator-max-microvolt = <1300000>;
regulator-always-on;
regulator-boot-on;
};
buck2_reg: BUCK2 {
regulator-name = "vdd_arm";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
regulator-boot-on;
};
buck3_reg: BUCK3 {
regulator-name = "vdd_int";
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
regulator-boot-on;
};
buck4_reg: BUCK4 {
regulator-name = "vdd_g3d";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1300000>;
regulator-always-on;
regulator-boot-on;
};
buck5_reg: BUCK5 {
regulator-name = "P1.8V_BUCK_OUT5";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
};
};
};
};

View File

@ -7,24 +7,28 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
*/
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h>
#include "exynos5250.dtsi"
/ {
model = "Google Snow";
compatible = "google,snow", "samsung,exynos5250";
compatible = "google,snow", "samsung,exynos5250", "samsung,exynos5";
aliases {
i2c0 = "/i2c@12c60000";
i2c1 = "/i2c@12c70000";
i2c2 = "/i2c@12c80000";
i2c3 = "/i2c@12c90000";
i2c4 = "/i2c@12ca0000";
i2c5 = "/i2c@12cb0000";
i2c6 = "/i2c@12cc0000";
i2c7 = "/i2c@12cd0000";
i2c0 = "/i2c@12C60000";
i2c1 = "/i2c@12C70000";
i2c2 = "/i2c@12C80000";
i2c3 = "/i2c@12C90000";
i2c4 = "/i2c@12CA0000";
i2c104 = &i2c_104;
i2c5 = "/i2c@12CB0000";
i2c6 = "/i2c@12CC0000";
i2c7 = "/i2c@12CD0000";
spi0 = "/spi@12d20000";
spi1 = "/spi@12d30000";
spi2 = "/spi@12d40000";
@ -39,18 +43,166 @@
i2s = "/sound@3830000";
};
i2c4: i2c@12ca0000 {
cros_ec: cros-ec@1e {
reg = <0x1e>;
compatible = "google,cros-ec-i2c";
i2c-max-frequency = <100000>;
u-boot,i2c-offset-len = <0>;
ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
memory {
reg = <0x40000000 0x80000000>;
};
chosen {
bootargs = "console=tty1";
stdout-path = "serial3:115200n8";
};
iram {
reg = <0x02020000 0x60000>;
};
config {
samsung,bl1-offset = <0x1400>;
samsung,bl2-offset = <0x3400>;
u-boot-memory = "/memory";
u-boot-offset = <0x3e00000 0x100000>;
};
flash {
reg = <0 0x100000>;
#address-cells = <1>;
#size-cells = <1>;
pre-boot {
label = "bl1 pre-boot";
reg = <0 0x2000>;
read-only;
filename = "e5250.nbl1.bin";
type = "blob exynos-bl1";
required;
};
power-regulator@48 {
compatible = "ti,tps65090";
reg = <0x48>;
spl {
label = "bl2 spl";
reg = <0x2000 0x4000>;
read-only;
filename = "bl2.bin";
type = "blob exynos-bl2 boot,dtb";
payload = "/flash/ro-boot";
required;
};
ro-boot {
label = "u-boot";
reg = <0x6000 0x9a000>;
read-only;
type = "blob boot,dtb";
required;
};
};
i2c-arbitrator {
compatible = "i2c-arb-gpio-challenge";
#address-cells = <1>;
#size-cells = <0>;
i2c-parent = <&{/i2c@12CA0000}>;
our-claim-gpio = <&gpf0 3 GPIO_ACTIVE_LOW>;
their-claim-gpios = <&gpe0 4 GPIO_ACTIVE_LOW>;
slew-delay-us = <10>;
wait-retry-us = <3000>;
wait-free-us = <50000>;
/* Use ID 104 as a hint that we're on physical bus 4 */
i2c_104: i2c@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
battery: sbs-battery@b {
compatible = "sbs,sbs-battery";
reg = <0xb>;
sbs,poll-retry-count = <1>;
};
cros_ec: embedded-controller {
compatible = "google,cros-ec-i2c";
reg = <0x1e>;
interrupts = <6 IRQ_TYPE_NONE>;
interrupt-parent = <&gpx1>;
wakeup-source;
i2c-max-frequency = <100000>;
u-boot,i2c-offset-len = <0>;
ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
};
power-regulator {
compatible = "ti,tps65090";
reg = <0x48>;
regulators {
dcdc1 {
ti,enable-ext-control;
};
dcdc2 {
ti,enable-ext-control;
};
dcdc3 {
ti,enable-ext-control;
};
fet1: fet1 {
regulator-name = "vcd_led";
ti,overcurrent-wait = <3>;
};
tps65090_fet2: fet2 {
regulator-name = "video_mid";
regulator-always-on;
ti,overcurrent-wait = <3>;
};
fet3 {
regulator-name = "wwan_r";
regulator-always-on;
ti,overcurrent-wait = <3>;
};
fet4 {
regulator-name = "sdcard";
ti,overcurrent-wait = <3>;
};
fet5 {
regulator-name = "camout";
regulator-always-on;
ti,overcurrent-wait = <3>;
};
fet6: fet6 {
regulator-name = "lcd_vdd";
ti,overcurrent-wait = <3>;
};
tps65090_fet7: fet7 {
regulator-name = "video_mid_1a";
regulator-always-on;
ti,overcurrent-wait = <3>;
};
ldo1 {
};
ldo2 {
};
};
charger {
compatible = "ti,tps65090-charger";
};
};
};
};
i2c@12CD0000 {
ptn3460: lvds-bridge@20 {
compatible = "nxp,ptn3460";
reg = <0x20>;
sleep-gpios = <&gpy2 5 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpx1 5 GPIO_ACTIVE_LOW>;
hotplug-gpios = <&gpx0 7 GPIO_ACTIVE_HIGH>;
edid-emulation = <5>;
};
soundcodec@22 {
reg = <0x22>;
compatible = "maxim,max98095-codec";
};
};
@ -66,6 +218,7 @@
spi-max-frequency = <1000000>;
spi-deactivate-delay = <100>;
/* Snow did support SPI but the released version used I2C */
embedded-controller {
compatible = "google,cros-ec-i2c";
reg = <0x1e>;
@ -85,28 +238,8 @@
status = "disabled";
};
i2c@12cd0000 {
soundcodec@22 {
reg = <0x22>;
compatible = "maxim,max98095-codec";
};
ptn3460-bridge@20 {
compatible = "nxp,ptn3460";
reg = <0x20>;
/*
* TODO(sjg@chromium.org): Use GPIOs here
* powerdown-gpio = <&gpy2 5 0>;
* reset-gpio = <&gpx1 5 0>;
* edid-emulation = <5>;
* pinctrl-names = "default";
* pinctrl-0 = <&ptn3460_gpios>;
*/
};
};
i2c@12c60000 {
pmic@9 {
i2c@12C60000 {
max77686@09 {
reg = <0x9>;
compatible = "maxim,max77686";
};
@ -199,4 +332,158 @@
};
&i2c_0 {
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <378000>;
max77686: max77686@09 {
compatible = "maxim,max77686";
interrupt-parent = <&gpx3>;
interrupts = <2 IRQ_TYPE_NONE>;
wakeup-source;
reg = <0x09>;
#clock-cells = <1>;
voltage-regulators {
ldo1_reg: LDO1 {
regulator-name = "P1.0V_LDO_OUT1";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-always-on;
};
ldo2_reg: LDO2 {
regulator-name = "P1.8V_LDO_OUT2";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
ldo3_reg: LDO3 {
regulator-name = "P1.8V_LDO_OUT3";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
ldo7_reg: LDO7 {
regulator-name = "P1.1V_LDO_OUT7";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
regulator-always-on;
};
ldo8_reg: LDO8 {
regulator-name = "P1.0V_LDO_OUT8";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-always-on;
};
ldo10_reg: LDO10 {
regulator-name = "P1.8V_LDO_OUT10";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
ldo12_reg: LDO12 {
regulator-name = "P3.0V_LDO_OUT12";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
regulator-always-on;
};
ldo14_reg: LDO14 {
regulator-name = "P1.8V_LDO_OUT14";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
ldo15_reg: LDO15 {
regulator-name = "P1.0V_LDO_OUT15";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-always-on;
};
ldo16_reg: LDO16 {
regulator-name = "P1.8V_LDO_OUT16";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
ldo17_reg: LDO17 {
regulator-name = "vdd_mydp";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
buck1_reg: BUCK1 {
regulator-name = "vdd_mif";
regulator-min-microvolt = <950000>;
regulator-max-microvolt = <1300000>;
regulator-always-on;
regulator-boot-on;
};
buck2_reg: BUCK2 {
regulator-name = "vdd_arm";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
regulator-boot-on;
};
buck3_reg: BUCK3 {
regulator-name = "vdd_int";
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
regulator-boot-on;
};
buck4_reg: BUCK4 {
regulator-name = "vdd_g3d";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1300000>;
regulator-always-on;
regulator-boot-on;
};
buck5_reg: BUCK5 {
regulator-name = "P1.8V_BUCK_OUT5";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
};
buck6_reg: BUCK6 {
regulator-name = "P1.35V_BUCK_OUT6";
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
};
buck7_reg: BUCK7 {
regulator-name = "P2.0V_BUCK_OUT7";
regulator-min-microvolt = <2000000>;
regulator-max-microvolt = <2000000>;
regulator-always-on;
};
buck8_reg: BUCK8 {
regulator-name = "P2.85V_BUCK_OUT8";
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <2850000>;
regulator-always-on;
};
};
};
};
#include "cros-ec-keyboard.dtsi"

View File

@ -0,0 +1,588 @@
/*
* Google Spring board device tree source
*
* Copyright (c) 2013 Google, Inc
* Copyright (c) 2014 SUSE LINUX Products GmbH
*
* SPDX-License-Identifier: GPL-2.0
*/
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h>
#include "exynos5250.dtsi"
/ {
model = "Google Spring";
compatible = "google,spring", "samsung,exynos5250", "samsung,exynos5";
aliases {
i2c0 = "/i2c@12C60000";
i2c1 = "/i2c@12C70000";
i2c2 = "/i2c@12C80000";
i2c3 = "/i2c@12C90000";
i2c4 = "/i2c@12CA0000";
i2c5 = "/i2c@12CB0000";
i2c6 = "/i2c@12CC0000";
i2c7 = "/i2c@12CD0000";
i2c104 = &cros_ec_ldo_tunnel;
spi0 = "/spi@12d20000";
spi1 = "/spi@12d30000";
spi2 = "/spi@12d40000";
spi3 = "/spi@131a0000";
spi4 = "/spi@131b0000";
mmc0 = "/mmc@12000000";
serial0 = "/serial@12C30000";
console = "/serial@12C30000";
i2s = "/sound@3830000";
};
memory {
reg = <0x40000000 0x80000000>;
};
flash@0 {
spl { /* spl size override */
size = <0x8000>;
};
};
chosen {
bootargs = "console=tty1";
stdout-path = "serial3:115200n8";
};
board-rev {
compatible = "google,board-revision";
google,board-rev-gpios = <&gpy4 0 0>, <&gpy4 1 0>,
<&gpy4 2 0>;
};
mmc@12200000 {
samsung,bus-width = <8>;
samsung,timing = <1 3 3>;
samsung,removable = <0>;
};
mmc@12210000 {
status = "disabled";
};
mmc@12220000 {
/* MMC2 pins are used as GPIO for eDP bridge */
status = "disabled";
};
mmc@12230000 {
status = "disabled";
};
ehci@12110000 {
samsung,vbus-gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
status = "okay";
};
xhci@12000000 {
samsung,vbus-gpio = <&gpx2 7 GPIO_ACTIVE_HIGH>;
};
spi@12d30000 {
spi-max-frequency = <50000000>;
firmware_storage_spi: flash@0 {
compatible = "spi-flash";
reg = <0>;
};
};
tmu@10060000 {
samsung,min-temp = <25>;
samsung,max-temp = <125>;
samsung,start-warning = <95>;
samsung,start-tripping = <105>;
samsung,hw-tripping = <110>;
samsung,efuse-min-value = <40>;
samsung,efuse-value = <55>;
samsung,efuse-max-value = <100>;
samsung,slope = <274761730>;
samsung,dc-value = <25>;
};
fimd@14400000 {
samsung,vl-freq = <60>;
samsung,vl-col = <1366>;
samsung,vl-row = <768>;
samsung,vl-width = <1366>;
samsung,vl-height = <768>;
samsung,vl-clkp;
samsung,vl-dp;
samsung,vl-hsp;
samsung,vl-vsp;
samsung,vl-bpix = <4>;
samsung,vl-hspw = <32>;
samsung,vl-hbpd = <80>;
samsung,vl-hfpd = <48>;
samsung,vl-vspw = <5>;
samsung,vl-vbpd = <14>;
samsung,vl-vfpd = <3>;
samsung,vl-cmd-allow-len = <0xf>;
samsung,winid = <0>;
samsung,interface-mode = <1>;
samsung,dp-enabled = <1>;
samsung,dual-lcd-enabled = <0>;
};
dp@145b0000 {
samsung,lt-status = <0>;
samsung,master-mode = <0>;
samsung,bist-mode = <0>;
samsung,bist-pattern = <0>;
samsung,h-sync-polarity = <0>;
samsung,v-sync-polarity = <0>;
samsung,interlaced = <0>;
samsung,color-space = <0>;
samsung,dynamic-range = <0>;
samsung,ycbcr-coeff = <0>;
samsung,color-depth = <1>;
};
};
&i2c_0 {
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <378000>;
s5m8767-pmic@66 {
compatible = "samsung,s5m8767-pmic";
reg = <0x66>;
interrupt-parent = <&gpx3>;
wakeup-source;
s5m8767,pmic-buck-dvs-gpios = <&gpd1 0 GPIO_ACTIVE_LOW>, /* DVS1 */
<&gpd1 1 GPIO_ACTIVE_LOW>, /* DVS2 */
<&gpd1 2 GPIO_ACTIVE_LOW>; /* DVS3 */
s5m8767,pmic-buck-ds-gpios = <&gpx2 3 GPIO_ACTIVE_LOW>, /* SET1 */
<&gpx2 4 GPIO_ACTIVE_LOW>, /* SET2 */
<&gpx2 5 GPIO_ACTIVE_LOW>; /* SET3 */
/*
* The following arrays of DVS voltages are not used, since we are
* not using GPIOs to control PMIC bucks, but they must be defined
* to please the driver.
*/
s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
<1250000>, <1200000>,
<1150000>, <1100000>,
<1000000>, <950000>;
s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
<1100000>, <1100000>,
<1000000>, <1000000>,
<1000000>, <1000000>;
s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
<1200000>, <1200000>,
<1200000>, <1200000>,
<1200000>, <1200000>;
clocks {
compatible = "samsung,s5m8767-clk";
#clock-cells = <1>;
clock-output-names = "en32khz_ap",
"en32khz_cp",
"en32khz_bt";
};
regulators {
ldo4_reg: LDO4 {
regulator-name = "P1.0V_LDO_OUT4";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-always-on;
op_mode = <0>;
};
ldo5_reg: LDO5 {
regulator-name = "P1.8V_LDO_OUT5";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
op_mode = <0>;
};
ldo6_reg: LDO6 {
regulator-name = "vdd_mydp";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
op_mode = <3>;
};
ldo7_reg: LDO7 {
regulator-name = "P1.1V_LDO_OUT7";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
regulator-always-on;
op_mode = <3>;
};
ldo8_reg: LDO8 {
regulator-name = "P1.0V_LDO_OUT8";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-always-on;
op_mode = <3>;
};
ldo10_reg: LDO10 {
regulator-name = "P1.8V_LDO_OUT10";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
op_mode = <3>;
};
ldo11_reg: LDO11 {
regulator-name = "P1.8V_LDO_OUT11";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
op_mode = <0>;
};
ldo12_reg: LDO12 {
regulator-name = "P3.0V_LDO_OUT12";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
regulator-always-on;
op_mode = <3>;
};
ldo13_reg: LDO13 {
regulator-name = "P1.8V_LDO_OUT13";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
op_mode = <0>;
};
ldo14_reg: LDO14 {
regulator-name = "P1.8V_LDO_OUT14";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
op_mode = <3>;
};
ldo15_reg: LDO15 {
regulator-name = "P1.0V_LDO_OUT15";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-always-on;
op_mode = <3>;
};
ldo16_reg: LDO16 {
regulator-name = "P1.8V_LDO_OUT16";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
op_mode = <3>;
};
ldo17_reg: LDO17 {
regulator-name = "P1.2V_LDO_OUT17";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
op_mode = <0>;
};
ldo25_reg: LDO25 {
regulator-name = "vdd_bridge";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
op_mode = <1>;
};
buck1_reg: BUCK1 {
regulator-name = "vdd_mif";
regulator-min-microvolt = <950000>;
regulator-max-microvolt = <1300000>;
regulator-always-on;
regulator-boot-on;
op_mode = <3>;
};
buck2_reg: BUCK2 {
regulator-name = "vdd_arm";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
regulator-boot-on;
op_mode = <3>;
};
buck3_reg: BUCK3 {
regulator-name = "vdd_int";
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
regulator-boot-on;
op_mode = <3>;
};
buck4_reg: BUCK4 {
regulator-name = "vdd_g3d";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1300000>;
regulator-boot-on;
op_mode = <3>;
};
buck5_reg: BUCK5 {
regulator-name = "P1.8V_BUCK_OUT5";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
op_mode = <1>;
};
buck6_reg: BUCK6 {
regulator-name = "P1.2V_BUCK_OUT6";
regulator-min-microvolt = <2050000>;
regulator-max-microvolt = <2050000>;
regulator-always-on;
regulator-boot-on;
op_mode = <0>;
};
buck9_reg: BUCK9 {
regulator-name = "vdd_ummc";
regulator-min-microvolt = <950000>;
regulator-max-microvolt = <3000000>;
regulator-always-on;
regulator-boot-on;
op_mode = <3>;
};
};
};
};
&i2c_1 {
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <378000>;
};
&i2c_2 {
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <66000>;
};
&i2c_3 {
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <66000>;
};
&i2c_4 {
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <66000>;
clock-frequency = <66000>;
cros_ec: embedded-controller {
compatible = "google,cros-ec-i2c";
reg = <0x1e>;
interrupts = <6 IRQ_TYPE_NONE>;
interrupt-parent = <&gpx1>;
wakeup-source;
u-boot,i2c-offset-len = <0>;
ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
cros_ec_ldo_tunnel: cros-ec-ldo-tunnel {
compatible = "google,cros-ec-ldo-tunnel";
#address-cells = <1>;
#size-cells = <0>;
power-regulator {
compatible = "ti,tps65090";
reg = <0x48>;
regulators {
dcdc1 {
ti,enable-ext-control;
};
dcdc2 {
ti,enable-ext-control;
};
dcdc3 {
ti,enable-ext-control;
};
fet1: fet1 {
regulator-name = "vcd_led";
ti,overcurrent-wait = <3>;
};
tps65090_fet2: fet2 {
regulator-name = "video_mid";
regulator-always-on;
ti,overcurrent-wait = <3>;
};
fet3 {
regulator-name = "wwan_r";
regulator-always-on;
ti,overcurrent-wait = <3>;
};
fet4 {
regulator-name = "sdcard";
ti,overcurrent-wait = <3>;
};
fet5 {
regulator-name = "camout";
regulator-always-on;
ti,overcurrent-wait = <3>;
};
fet6: fet6 {
regulator-name = "lcd_vdd";
ti,overcurrent-wait = <3>;
};
tps65090_fet7: fet7 {
regulator-name = "video_mid_1a";
regulator-always-on;
ti,overcurrent-wait = <3>;
};
ldo1 {
};
ldo2 {
};
};
};
};
};
};
&i2c_5 {
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <66000>;
};
&i2c_7 {
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <66000>;
ps8622-bridge@8 {
compatible = "parade,ps8622";
reg = <0x8>;
sleep-gpios = <&gpc3 6 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpc3 1 GPIO_ACTIVE_LOW>;
hotplug-gpios = <&gpc3 0 GPIO_ACTIVE_HIGH>;
power-supply = <&ldo6_reg>;
parade,regs = /bits/ 8 <
0x02 0xa1 0x01 /* HPD low */
/*
* SW setting: [1:0] SW output 1.2V voltage is
* lower to 96%
*/
0x04 0x14 0x01
/* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */
0x04 0xe3 0x20
0x04 0xe2 0x80 /* [7] RCO SS enable */
/*
* RPHY Setting: [3:2] CDR tune wait cycle before
* measure for fine tune b00: 1us,
* 01: 0.5us, 10:2us, 11:4us
*/
0x04 0x8a 0x0c
0x04 0x89 0x08 /* [3] RFD always on */
/*
* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times
*/
0x04 0x71 0x2d
/* 2.7G CDR settings */
0x04 0x7d 0x07 /* NOF=40LSB for HBR CDR setting */
0x04 0x7b 0x00 /* [1:0] Fmin=+4bands */
0x04 0x7a 0xfd /* [7:5] DCO_FTRNG=+-40% */
/*
* 1.62G CDR settings:
* [5:2]NOF=64LSB [1:0]DCO scale is 2/5
*/
0x04 0xc0 0x12
0x04 0xc1 0x92 /* Gitune=-37% */
0x04 0xc2 0x1c /* Fbstep=100% */
0x04 0x32 0x80 /* [7] LOS signal disable */
/* RPIO Setting */
/* [7:4] LVDS driver bias current 75% (250mV swing) */
0x04 0x00 0xb0
/* [7:6] Right-bar GPIO output strength is 8mA */
0x04 0x15 0x40
/* EQ Training State Machine Setting */
0x04 0x54 0x10 /* RCO calibration start */
/* [4:0] MAX_LANE_COUNT set to one lane */
0x01 0x02 0x81
/* [4:0] LANE_COUNT_SET set to one lane */
0x01 0x21 0x81
0x00 0x52 0x20
0x00 0xf1 0x03 /* HPD CP toggle enable */
0x00 0x62 0x41
/* Counter number add 1ms counter delay */
0x00 0xf6 0x01
/*
* [6]PWM function control by DPCD0040f[7], default
* is PWM block always works
*/
0x00 0x77 0x06
0x00 0x4c 0x04
/*
* 04h Adjust VTotal tolerance to fix the 30Hz no-
* display issue
* DPCD00400='h00 Parade OUI = 'h001cf8
*/
0x01 0xc0 0x00
0x01 0xc1 0x1c /* DPCD00401='h1c */
0x01 0xc2 0xf8 /* DPCD00402='hf8 */
/* DPCD403~408 = ASCII code D2SLV5='h4432534c5635 */
0x01 0xc3 0x44
0x01 0xc4 0x32 /* DPCD404 */
0x01 0xc5 0x53 /* DPCD405 */
0x01 0xc6 0x4c /* DPCD406 */
0x01 0xc7 0x56 /* DPCD407 */
0x01 0xc8 0x35 /* DPCD408 */
/* DPCD40A Initial Code major revision '01' */
0x01 0xca 0x01
/* DPCD40B Initial Code minor revision '05' */
0x01 0xcb 0x05
0x01 0xa5 0xa0 /* DPCD720, Select internal PWM */
/*
* 0xff for 100% PWM of brightness, 0h for 0% brightness
*/
0x01 0xa7 0x00
/*
* Set LVDS output as 6bit-VESA mapping, single LVDS
* channel
*/
0x01 0xcc 0x13
0x02 0xb1 0x20 /* Enable SSC set by register */
/* Set SSC enabled and +/-1% central spreading */
0x04 0x10 0x16
0x04 0x59 0x60 /* MPU Clock source: LC => RCO */
0x04 0x54 0x14 /* LC -> RCO */
0x02 0xa1 0x91>; /* HPD high */
};
soundcodec@20 {
reg = <0x20>;
compatible = "maxim,max98088-codec";
};
};
#include "cros-ec-keyboard.dtsi"

View File

@ -47,36 +47,36 @@
interrupts = <0 47 0>;
};
i2c@12ca0000 {
#address-cells = <1>;
#size-cells = <0>;
i2c_4: i2c@12CA0000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12CA0000 0x100>;
interrupts = <0 60 0>;
};
i2c@12cb0000 {
#address-cells = <1>;
#size-cells = <0>;
};
i2c_5: i2c@12CB0000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12CB0000 0x100>;
interrupts = <0 61 0>;
};
i2c@12cc0000 {
#address-cells = <1>;
#size-cells = <0>;
};
i2c_6: i2c@12CC0000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12CC0000 0x100>;
interrupts = <0 62 0>;
};
i2c@12cd0000 {
#address-cells = <1>;
#size-cells = <0>;
};
i2c_7: i2c@12CD0000 {
compatible = "samsung,s3c2440-i2c";
reg = <0x12CD0000 0x100>;
interrupts = <0 63 0>;
#address-cells = <1>;
#size-cells = <0>;
};
sound@3830000 {

View File

@ -25,7 +25,8 @@
aliases {
serial0 = "/serial@12C30000";
console = "/serial@12C30000";
pmic = "/i2c@12ca0000";
pmic = "/i2c@12CA0000";
i2c104 = &i2c_tunnel;
};
dmc {
@ -49,7 +50,7 @@
};
/* MAX77802 is on i2c bus 4 */
i2c@12ca0000 {
i2c@12CA0000 {
clock-frequency = <400000>;
power-regulator@9 {
compatible = "maxim,max77802-pmic";
@ -57,18 +58,136 @@
};
};
i2c@12cd0000 { /* i2c7 */
i2c@12CD0000 { /* i2c7 */
clock-frequency = <100000>;
soundcodec@20 {
reg = <0x20>;
compatible = "maxim,max98090-codec";
};
edp-lvds-bridge@48 {
compatible = "parade,ps8625";
reg = <0x48>;
sleep-gpio = <&gpx3 5 GPIO_ACTIVE_HIGH>;
reset-gpio = <&gpy7 7 GPIO_ACTIVE_HIGH>;
edp-lvds-bridge@48 {
compatible = "parade,ps8625";
reg = <0x48>;
sleep-gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpy7 7 GPIO_ACTIVE_LOW>;
parade,regs = /bits/ 8 <
0x02 0xa1 0x01 /* HPD low */
/*
* SW setting
* [1:0] SW output 1.2V voltage is lower to 96%
*/
0x04 0x14 0x01
/*
* RCO SS setting
* [5:4] = b01 0.5%, b10 1%, b11 1.5%
*/
0x04 0xe3 0x20
0x04 0xe2 0x80 /* [7] RCO SS enable */
/*
* RPHY Setting
* [3:2] CDR tune wait cycle before
* measure for fine tune b00: 1us,
* 01: 0.5us, 10:2us, 11:4us.
*/
0x04 0x8a 0x0c
0x04 0x89 0x08 /* [3] RFD always on */
/*
* CTN lock in/out:
* 20000ppm/80000ppm. Lock out 2
* times.
*/
0x04 0x71 0x2d
/*
* 2.7G CDR settings
* NOF=40LSB for HBR CDR setting
*/
0x04 0x7d 0x07
0x04 0x7b 0x00 /* [1:0] Fmin=+4bands */
0x04 0x7a 0xfd /* [7:5] DCO_FTRNG=+-40% */
/*
* 1.62G CDR settings
* [5:2]NOF=64LSB [1:0]DCO scale is 2/5
*/
0x04 0xc0 0x12
0x04 0xc1 0x92 /* Gitune=-37% */
0x04 0xc2 0x1c /* Fbstep=100% */
0x04 0x32 0x80 /* [7]LOS signal disable */
/*
* RPIO Setting
* [7:4] LVDS driver bias current :
* 75% (250mV swing)
*/
0x04 0x00 0xb0
/*
* [7:6] Right-bar GPIO output strength is 8mA
*/
0x04 0x15 0x40
/* EQ Training State Machine Setting */
0x04 0x54 0x10 /* RCO calibration start */
/* [4:0] MAX_LANE_COUNT set to one lane */
0x01 0x02 0x81
/* [4:0] LANE_COUNT_SET set to one lane */
0x01 0x21 0x81
0x00 0x52 0x20
0x00 0xf1 0x03 /* HPD CP toggle enable */
0x00 0x62 0x41
/* Counter number add 1ms counter delay */
0x00 0xf6 0x01
/*
* [6]PWM function control by
* DPCD0040f[7], default is PWM
* block always works.
*/
0x00 0x77 0x06
/*
* 04h Adjust VTotal tolerance to
* fix the 30Hz no display issue
*/
0x00 0x4c 0x04
/* DPCD00400='h00, Parade OUI = 'h001cf8 */
0x01 0xc0 0x00
0x01 0xc1 0x1c /* DPCD00401='h1c */
0x01 0xc2 0xf8 /* DPCD00402='hf8 */
/*
* DPCD403~408 = ASCII code
* D2SLV5='h4432534c5635
*/
0x01 0xc3 0x44
0x01 0xc4 0x32 /* DPCD404 */
0x01 0xc5 0x53 /* DPCD405 */
0x01 0xc6 0x4c /* DPCD406 */
0x01 0xc7 0x56 /* DPCD407 */
0x01 0xc8 0x35 /* DPCD408 */
/*
* DPCD40A, Initial Code major revision
* '01'
*/
0x01 0xca 0x01
/* DPCD40B Initial Code minor revision '05' */
0x01 0xcb 0x05
/* DPCD720 Select internal PWM */
0x01 0xa5 0xa0
/*
* FFh for 100% PWM of brightness, 0h for 0%
* brightness
*/
0x01 0xa7 0xff
/*
* Set LVDS output as 6bit-VESA mapping,
* single LVDS channel
*/
0x01 0xcc 0x13
/* Enable SSC set by register */
0x02 0xb1 0x20
/*
* Set SSC enabled and +/-1% central
* spreading
*/
0x04 0x10 0x16
/* MPU Clock source: LC => RCO */
0x04 0x59 0x60
0x04 0x54 0x14 /* LC -> RCO */
0x02 0xa1 0x91>; /* HPD high */
};
};
@ -76,7 +195,7 @@
samsung,codec-type = "max98090";
};
i2c@12e10000 { /* i2c9 */
i2c@12E10000 { /* i2c9 */
clock-frequency = <400000>;
tpm@20 {
compatible = "infineon,slb9645tt";
@ -101,30 +220,6 @@
};
};
spi@12d40000 { /* spi2 */
spi-max-frequency = <4000000>;
spi-deactivate-delay = <200>;
cros_ec: cros-ec@0 {
compatible = "google,cros-ec-spi";
reg = <0>;
spi-half-duplex;
spi-max-timeout-ms = <1100>;
ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
/*
* This describes the flash memory within the EC. Note
* that the STM32L flash erases to 0, not 0xff.
*/
#address-cells = <1>;
#size-cells = <1>;
flash@8000000 {
reg = <0x08000000 0x20000>;
erase-value = <0>;
};
};
};
xhci@12000000 {
samsung,vbus-gpio = <&gph0 0 GPIO_ACTIVE_HIGH>;
};
@ -159,4 +254,103 @@
};
};
&spi_2 {
spi-max-frequency = <3125000>;
spi-deactivate-delay = <200>;
status = "okay";
num-cs = <1>;
samsung,spi-src-clk = <0>;
cs-gpios = <&gpb1 2 0>;
cros_ec: cros-ec@0 {
compatible = "google,cros-ec-spi";
interrupt-parent = <&gpx1>;
interrupts = <5 0>;
reg = <0>;
spi-half-duplex;
spi-max-timeout-ms = <1100>;
ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
#address-cells = <1>;
#size-cells = <1>;
/*
* This describes the flash memory within the EC. Note
* that the STM32L flash erases to 0, not 0xff.
*/
flash@8000000 {
reg = <0x08000000 0x20000>;
erase-value = <0>;
};
controller-data {
samsung,spi-feedback-delay = <1>;
};
i2c_tunnel: i2c-tunnel {
compatible = "google,cros-ec-i2c-tunnel";
#address-cells = <1>;
#size-cells = <0>;
google,remote-bus = <0>;
battery: sbs-battery@b {
compatible = "sbs,sbs-battery";
reg = <0xb>;
sbs,poll-retry-count = <1>;
sbs,i2c-retry-count = <2>;
};
power-regulator@48 {
compatible = "ti,tps65090";
reg = <0x48>;
regulators {
tps65090_dcdc1: dcdc1 {
ti,enable-ext-control;
};
tps65090_dcdc2: dcdc2 {
ti,enable-ext-control;
};
tps65090_dcdc3: dcdc3 {
ti,enable-ext-control;
};
tps65090_fet1: fet1 {
regulator-name = "vcd_led";
};
tps65090_fet2: fet2 {
regulator-name = "video_mid";
regulator-always-on;
};
tps65090_fet3: fet3 {
regulator-name = "wwan_r";
regulator-always-on;
};
tps65090_fet4: fet4 {
regulator-name = "sdcard";
regulator-always-on;
};
tps65090_fet5: fet5 {
regulator-name = "camout";
regulator-always-on;
};
tps65090_fet6: fet6 {
regulator-name = "lcd_vdd";
};
tps65090_fet7: fet7 {
regulator-name = "video_mid_1a";
regulator-always-on;
};
tps65090_ldo1: ldo1 {
};
tps65090_ldo2: ldo2 {
};
};
charger {
compatible = "ti,tps65090-charger";
};
};
};
};
};
#include "cros-ec-keyboard.dtsi"

View File

@ -37,7 +37,7 @@
};
/* s2mps11 is on i2c bus 4 */
i2c@12ca0000 {
i2c@12CA0000 {
#address-cells = <1>;
#size-cells = <0>;
pmic@66 {
@ -82,7 +82,7 @@
samsung,codec-type = "wm8994";
};
i2c@12c70000 {
i2c@12C70000 {
soundcodec@1a {
reg = <0x1a>;
compatible = "wolfson,wm8994-codec";

View File

@ -14,17 +14,17 @@
};
aliases {
i2c0 = "/i2c@12c60000";
i2c1 = "/i2c@12c70000";
i2c2 = "/i2c@12c80000";
i2c3 = "/i2c@12c90000";
i2c4 = "/i2c@12ca0000";
i2c5 = "/i2c@12cb0000";
i2c6 = "/i2c@12cc0000";
i2c7 = "/i2c@12cd0000";
i2c8 = "/i2c@12e00000";
i2c9 = "/i2c@12e10000";
i2c10 = "/i2c@12e20000";
i2c0 = "/i2c@12C60000";
i2c1 = "/i2c@12C70000";
i2c2 = "/i2c@12C80000";
i2c3 = "/i2c@12C90000";
i2c4 = "/i2c@12CA0000";
i2c5 = "/i2c@12CB0000";
i2c6 = "/i2c@12CC0000";
i2c7 = "/i2c@12CD0000";
i2c8 = "/i2c@12E00000";
i2c9 = "/i2c@12E10000";
i2c10 = "/i2c@12E20000";
pinctrl0 = &pinctrl_0;
pinctrl1 = &pinctrl_1;
pinctrl2 = &pinctrl_2;
@ -42,7 +42,7 @@
xhci1 = "/xhci@12400000";
};
i2c@12ca0000 {
i2c@12CA0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@ -50,7 +50,7 @@
interrupts = <0 60 0>;
};
i2c@12cb0000 {
i2c@12CB0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@ -58,7 +58,7 @@
interrupts = <0 61 0>;
};
i2c@12cc0000 {
i2c@12CC0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@ -66,7 +66,7 @@
interrupts = <0 62 0>;
};
i2c@12cd0000 {
i2c@12CD0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@ -74,7 +74,7 @@
interrupts = <0 63 0>;
};
i2c@12e00000 {
i2c@12E00000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@ -82,7 +82,7 @@
interrupts = <0 87 0>;
};
i2c@12e10000 {
i2c@12E10000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";
@ -90,7 +90,7 @@
interrupts = <0 88 0>;
};
i2c@12e20000 {
i2c@12E20000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,exynos5-hsi2c";

View File

@ -25,7 +25,8 @@
aliases {
serial0 = "/serial@12C30000";
console = "/serial@12C30000";
pmic = "/i2c@12ca0000";
pmic = "/i2c@12CA0000";
i2c104 = &i2c_tunnel;
};
dmc {
@ -49,7 +50,7 @@
};
/* MAX77802 is on i2c bus 4 */
i2c@12ca0000 {
i2c@12CA0000 {
clock-frequency = <400000>;
power-regulator@9 {
compatible = "maxim,max77802-pmic";
@ -57,7 +58,7 @@
};
};
i2c@12cd0000 { /* i2c7 */
i2c@12CD0000 { /* i2c7 */
clock-frequency = <100000>;
soundcodec@20 {
reg = <0x20>;
@ -69,7 +70,7 @@
samsung,codec-type = "max98090";
};
i2c@12e10000 { /* i2c9 */
i2c@12E10000 { /* i2c9 */
clock-frequency = <400000>;
tpm@20 {
compatible = "infineon,slb9645tt";
@ -93,29 +94,6 @@
};
};
spi@12d40000 { /* spi2 */
spi-max-frequency = <4000000>;
spi-deactivate-delay = <200>;
cros_ec: cros-ec@0 {
compatible = "google,cros-ec-spi";
reg = <0>;
spi-half-duplex;
spi-max-timeout-ms = <1100>;
ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
/*
* This describes the flash memory within the EC. Note
* that the STM32L flash erases to 0, not 0xff.
*/
#address-cells = <1>;
#size-cells = <1>;
flash@8000000 {
reg = <0x08000000 0x20000>;
erase-value = <0>;
};
};
};
xhci@12000000 {
samsung,vbus-gpio = <&gph0 0 GPIO_ACTIVE_HIGH>;
};
@ -153,4 +131,103 @@
};
};
&spi_2 {
spi-max-frequency = <3125000>;
spi-deactivate-delay = <200>;
status = "okay";
num-cs = <1>;
samsung,spi-src-clk = <0>;
cs-gpios = <&gpb1 2 0>;
cros_ec: cros-ec@0 {
compatible = "google,cros-ec-spi";
interrupt-parent = <&gpx1>;
interrupts = <5 0>;
reg = <0>;
spi-half-duplex;
spi-max-timeout-ms = <1100>;
ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
/*
* This describes the flash memory within the EC. Note
* that the STM32L flash erases to 0, not 0xff.
*/
#address-cells = <1>;
#size-cells = <1>;
flash@8000000 {
reg = <0x08000000 0x20000>;
erase-value = <0>;
};
controller-data {
samsung,spi-feedback-delay = <1>;
};
i2c_tunnel: i2c-tunnel {
compatible = "google,cros-ec-i2c-tunnel";
#address-cells = <1>;
#size-cells = <0>;
google,remote-bus = <0>;
battery: sbs-battery@b {
compatible = "sbs,sbs-battery";
reg = <0xb>;
sbs,poll-retry-count = <1>;
sbs,i2c-retry-count = <2>;
};
power-regulator@48 {
compatible = "ti,tps65090";
reg = <0x48>;
regulators {
tps65090_dcdc1: dcdc1 {
ti,enable-ext-control;
};
tps65090_dcdc2: dcdc2 {
ti,enable-ext-control;
};
tps65090_dcdc3: dcdc3 {
ti,enable-ext-control;
};
tps65090_fet1: fet1 {
regulator-name = "vcd_led";
};
tps65090_fet2: fet2 {
regulator-name = "video_mid";
regulator-always-on;
};
tps65090_fet3: fet3 {
regulator-name = "wwan_r";
regulator-always-on;
};
tps65090_fet4: fet4 {
regulator-name = "sdcard";
regulator-always-on;
};
tps65090_fet5: fet5 {
regulator-name = "camout";
regulator-always-on;
};
tps65090_fet6: fet6 {
regulator-name = "lcd_vdd";
};
tps65090_fet7: fet7 {
regulator-name = "video_mid_1a";
regulator-always-on;
};
tps65090_ldo1: ldo1 {
};
tps65090_ldo2: ldo2 {
};
};
charger {
compatible = "ti,tps65090-charger";
};
};
};
};
};
#include "cros-ec-keyboard.dtsi"

View File

@ -197,6 +197,4 @@ unsigned int exynos_init_dp(void)
}
#endif
void exynos_set_dp_platform_data(struct exynos_dp_platform_data *pd);
#endif /* _DP_INFO_H */

View File

@ -53,6 +53,7 @@ enum periph_id {
PERIPH_ID_PWM2,
PERIPH_ID_PWM3,
PERIPH_ID_PWM4,
PERIPH_ID_DPHPD,
PERIPH_ID_I2C10 = 203,
PERIPH_ID_NONE = -1,

View File

@ -128,6 +128,15 @@ car_init_ret:
andl $0xfffffff0, %esp
post_code(POST_START_STACK)
/*
* Debug UART is available here although it may not be plumbed out
* to pins depending on the board. To use it:
*
* call debug_uart_init
* mov $'a', %eax
* call printch
*/
/* Zero the global data since it won't happen later */
xorl %eax, %eax
movl $GENERATED_GBL_DATA_SIZE, %ecx

View File

@ -11,4 +11,5 @@ obj-$(CONFIG_MISC_COMMON) += misc.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_BOARD_COMMON) += board.o
obj-$(CONFIG_EXYNOS5_DT) += exynos5-dt.o
endif

View File

@ -152,13 +152,14 @@ int board_early_init_f(void)
board_i2c_init(gd->fdt_blob);
#endif
#if defined(CONFIG_OF_CONTROL) && defined(CONFIG_EXYNOS_FB)
/*
* board_init_f(arch/arm/lib/board.c) calls lcd_setmem() which needs
* panel_info.vl_col, panel_info.vl_row and panel_info.vl_bpix, to reserve
* FB memory at a very early stage. So, we need to fill panel_info.vl_col,
* panel_info.vl_row and panel_info.vl_bpix before lcd_setmem() is called.
*/
#if defined(CONFIG_EXYNOS_FB)
/*
* board_init_f(arch/arm/lib/board.c) calls lcd_setmem() which needs
* panel_info.vl_col, panel_info.vl_row and panel_info.vl_bpix,
* to reserve frame-buffer memory at a very early stage. So, we need
* to fill panel_info.vl_col, panel_info.vl_row and panel_info.vl_bpix
* before lcd_setmem() is called.
*/
err = exynos_lcd_early_init(gd->fdt_blob);
if (err) {
debug("LCD early init failed\n");
@ -179,7 +180,6 @@ int power_init_board(void)
}
#endif
#ifdef CONFIG_OF_CONTROL
#ifdef CONFIG_SMC911X
static int decode_sromc(const void *blob, struct fdt_sromc *config)
{
@ -310,7 +310,6 @@ int checkboard(void)
return 0;
}
#endif
#endif /* CONFIG_OF_CONTROL */
#ifdef CONFIG_BOARD_LATE_INIT
int board_late_init(void)

View File

@ -0,0 +1,362 @@
/*
* Copyright (C) 2012 Samsung Electronics
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <dwc3-uboot.h>
#include <fdtdec.h>
#include <asm/io.h>
#include <errno.h>
#include <i2c.h>
#include <mmc.h>
#include <netdev.h>
#include <samsung-usb-phy-uboot.h>
#include <spi.h>
#include <usb.h>
#include <video_bridge.h>
#include <asm/gpio.h>
#include <asm/arch/cpu.h>
#include <asm/arch/dwmmc.h>
#include <asm/arch/mmc.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/power.h>
#include <asm/arch/sromc.h>
#include <power/pmic.h>
#include <power/max77686_pmic.h>
#include <power/regulator.h>
#include <power/s5m8767.h>
#include <tmu.h>
DECLARE_GLOBAL_DATA_PTR;
static void board_enable_audio_codec(void)
{
int node, ret;
struct gpio_desc en_gpio;
node = fdtdec_next_compatible(gd->fdt_blob, 0,
COMPAT_SAMSUNG_EXYNOS5_SOUND);
if (node <= 0)
return;
ret = gpio_request_by_name_nodev(gd->fdt_blob, node,
"codec-enable-gpio", 0, &en_gpio,
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
if (ret == -FDT_ERR_NOTFOUND)
return;
/* Turn on the GPIO which connects to the codec's "enable" line. */
gpio_set_pull(gpio_get_number(&en_gpio), S5P_GPIO_PULL_NONE);
#ifdef CONFIG_SOUND_MAX98095
/* Enable MAX98095 Codec */
gpio_request(EXYNOS5_GPIO_X17, "max98095_enable");
gpio_direction_output(EXYNOS5_GPIO_X17, 1);
gpio_set_pull(EXYNOS5_GPIO_X17, S5P_GPIO_PULL_NONE);
#endif
}
int exynos_init(void)
{
board_enable_audio_codec();
return 0;
}
static int exynos_set_regulator(const char *name, uint uv)
{
struct udevice *dev;
int ret;
ret = regulator_get_by_platname(name, &dev);
if (ret) {
debug("%s: Cannot find regulator %s\n", __func__, name);
return ret;
}
ret = regulator_set_value(dev, uv);
if (ret) {
debug("%s: Cannot set regulator %s\n", __func__, name);
return ret;
}
return 0;
}
int exynos_power_init(void)
{
struct udevice *dev;
int ret;
ret = pmic_get("max77686", &dev);
if (!ret) {
/* TODO(sjg@chromium.org): Move into the clock/pmic API */
ret = pmic_clrsetbits(dev, MAX77686_REG_PMIC_32KHZ, 0,
MAX77686_32KHCP_EN);
if (ret)
return ret;
ret = pmic_clrsetbits(dev, MAX77686_REG_PMIC_BBAT, 0,
MAX77686_BBCHOSTEN | MAX77686_BBCVS_3_5V);
if (ret)
return ret;
} else {
ret = pmic_get("s5m8767-pmic", &dev);
/* TODO(sjg@chromium.org): Use driver model to access clock */
#ifdef CONFIG_PMIC_S5M8767
if (!ret)
s5m8767_enable_32khz_cp(dev);
#endif
}
if (ret == -ENODEV)
return 0;
ret = regulators_enable_boot_on(false);
if (ret)
return ret;
ret = exynos_set_regulator("vdd_mif", 1100000);
if (ret)
return ret;
/*
* This would normally be 1.3V, but since we are running slowly 1V
* is enough. For spring it helps reduce CPU temperature and avoid
* hangs with the case open.
*/
ret = exynos_set_regulator("vdd_arm", 1000000);
if (ret)
return ret;
ret = exynos_set_regulator("vdd_int", 1012500);
if (ret)
return ret;
ret = exynos_set_regulator("vdd_g3d", 1200000);
if (ret)
return ret;
return 0;
}
int board_get_revision(void)
{
return 0;
}
#ifdef CONFIG_LCD
static int board_dp_bridge_init(struct udevice *dev)
{
const int max_tries = 10;
int num_tries;
int ret;
debug("%s\n", __func__);
ret = video_bridge_attach(dev);
if (ret) {
debug("video bridge init failed: %d\n", ret);
return ret;
}
/*
* We need to wait for 90ms after bringing up the bridge since there
* is a phantom "high" on the HPD chip during its bootup. The phantom
* high comes within 7ms of de-asserting PD and persists for at least
* 15ms. The real high comes roughly 50ms after PD is de-asserted. The
* phantom high makes it hard for us to know when the NXP chip is up.
*/
mdelay(90);
for (num_tries = 0; num_tries < max_tries; num_tries++) {
/* Check HPD. If it's high, or we don't have it, all is well */
ret = video_bridge_check_attached(dev);
if (!ret || ret == -ENOENT)
return 0;
debug("%s: eDP bridge failed to come up; try %d of %d\n",
__func__, num_tries, max_tries);
}
/* Immediately go into bridge reset if the hp line is not high */
return -EIO;
}
static int board_dp_bridge_setup(const void *blob)
{
const int max_tries = 2;
int num_tries;
struct udevice *dev;
int ret;
/* Configure I2C registers for Parade bridge */
ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &dev);
if (ret) {
debug("video bridge init failed: %d\n", ret);
return ret;
}
if (strncmp(dev->driver->name, "parade", 6)) {
/* Mux HPHPD to the special hotplug detect mode */
exynos_pinmux_config(PERIPH_ID_DPHPD, 0);
}
for (num_tries = 0; num_tries < max_tries; num_tries++) {
ret = board_dp_bridge_init(dev);
if (!ret)
return 0;
if (num_tries == max_tries - 1)
break;
/*
* If we're here, the bridge chip failed to initialise.
* Power down the bridge in an attempt to reset.
*/
video_bridge_set_active(dev, false);
/*
* Arbitrarily wait 300ms here with DP_N low. Don't know for
* sure how long we should wait, but we're being paranoid.
*/
mdelay(300);
}
return ret;
}
void exynos_cfg_lcd_gpio(void)
{
/* For Backlight */
gpio_request(EXYNOS5_GPIO_B20, "lcd_backlight");
gpio_cfg_pin(EXYNOS5_GPIO_B20, S5P_GPIO_OUTPUT);
gpio_set_value(EXYNOS5_GPIO_B20, 1);
}
void exynos_set_dp_phy(unsigned int onoff)
{
set_dp_phy_ctrl(onoff);
}
static int board_dp_set_backlight(int percent)
{
struct udevice *dev;
int ret;
ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &dev);
if (!ret)
ret = video_bridge_set_backlight(dev, percent);
return ret;
}
void exynos_backlight_on(unsigned int on)
{
struct udevice *dev;
int ret;
debug("%s(%u)\n", __func__, on);
if (!on)
return;
ret = regulator_get_by_platname("vcd_led", &dev);
if (!ret)
ret = regulator_set_enable(dev, true);
if (ret)
debug("Failed to enable backlight: ret=%d\n", ret);
/* T5 in the LCD timing spec (defined as > 10ms) */
mdelay(10);
/* board_dp_backlight_pwm */
gpio_direction_output(EXYNOS5_GPIO_B20, 1);
/* T6 in the LCD timing spec (defined as > 10ms) */
mdelay(10);
/* try to set the backlight in the bridge registers */
ret = board_dp_set_backlight(80);
/* if we have no bridge or it does not support backlight, use a GPIO */
if (ret == -ENODEV || ret == -ENOSYS) {
gpio_request(EXYNOS5_GPIO_X30, "board_dp_backlight_en");
gpio_direction_output(EXYNOS5_GPIO_X30, 1);
}
}
void exynos_lcd_power_on(void)
{
struct udevice *dev;
int ret;
debug("%s\n", __func__);
ret = regulator_get_by_platname("lcd_vdd", &dev);
if (!ret)
ret = regulator_set_enable(dev, true);
if (ret)
debug("Failed to enable LCD panel: ret=%d\n", ret);
ret = board_dp_bridge_setup(gd->fdt_blob);
if (ret && ret != -ENODEV)
printf("LCD bridge failed to enable: %d\n", ret);
}
#endif
#ifdef CONFIG_USB_DWC3
static struct dwc3_device dwc3_device_data = {
.maximum_speed = USB_SPEED_SUPER,
.base = 0x12400000,
.dr_mode = USB_DR_MODE_PERIPHERAL,
.index = 0,
};
int usb_gadget_handle_interrupts(void)
{
dwc3_uboot_handle_interrupt(0);
return 0;
}
int board_usb_init(int index, enum usb_init_type init)
{
struct exynos_usb3_phy *phy = (struct exynos_usb3_phy *)
samsung_get_base_usb3_phy();
if (!phy) {
error("usb3 phy not supported");
return -ENODEV;
}
set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
exynos5_usb3_phy_init(phy);
return dwc3_uboot_init(&dwc3_device_data);
}
#endif
#ifdef CONFIG_SET_DFU_ALT_INFO
char *get_dfu_alt_system(char *interface, char *devstr)
{
return getenv("dfu_alt_system");
}
char *get_dfu_alt_boot(char *interface, char *devstr)
{
struct mmc *mmc;
char *alt_boot;
int dev_num;
dev_num = simple_strtoul(devstr, NULL, 10);
mmc = find_mmc_device(dev_num);
if (!mmc)
return NULL;
if (mmc_init(mmc))
return NULL;
if (IS_SD(mmc))
alt_boot = CONFIG_DFU_ALT_BOOT_SD;
else
alt_boot = CONFIG_DFU_ALT_BOOT_EMMC;
return alt_boot;
}
#endif

View File

@ -23,3 +23,16 @@ config SYS_CONFIG_NAME
default "snow"
endif
if TARGET_SPRING
config SYS_BOARD
default "smdk5250"
config SYS_VENDOR
default "samsung"
config SYS_CONFIG_NAME
default "spring"
endif

View File

@ -10,3 +10,9 @@ M: Akshay Saraswat <akshay.s@samsung.com>
S: Maintained
F: include/configs/snow.h
F: configs/snow_defconfig
SPRING BOARD
M: Simon Glass <sjg@chromium.org>
S: Maintained
F: include/configs/spring.h
F: configs/spring_defconfig

View File

@ -5,7 +5,3 @@
#
obj-y += smdk5250_spl.o
ifndef CONFIG_SPL_BUILD
obj-y += exynos5-dt.o
endif

View File

@ -1,306 +0,0 @@
/*
* Copyright (C) 2012 Samsung Electronics
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <fdtdec.h>
#include <asm/io.h>
#include <errno.h>
#include <i2c.h>
#include <netdev.h>
#include <spi.h>
#include <asm/gpio.h>
#include <asm/arch/cpu.h>
#include <asm/arch/dwmmc.h>
#include <asm/arch/mmc.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/power.h>
#include <asm/arch/sromc.h>
#include <power/pmic.h>
#include <power/max77686_pmic.h>
#include <power/tps65090_pmic.h>
#include <tmu.h>
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_SOUND_MAX98095
static void board_enable_audio_codec(void)
{
/* Enable MAX98095 Codec */
gpio_request(EXYNOS5_GPIO_X17, "max98095_enable");
gpio_direction_output(EXYNOS5_GPIO_X17, 1);
gpio_set_pull(EXYNOS5_GPIO_X17, S5P_GPIO_PULL_NONE);
}
#endif
int exynos_init(void)
{
#ifdef CONFIG_SOUND_MAX98095
board_enable_audio_codec();
#endif
return 0;
}
#if defined(CONFIG_POWER)
#ifdef CONFIG_POWER_MAX77686
static int pmic_reg_update(struct pmic *p, int reg, uint regval)
{
u32 val;
int ret = 0;
ret = pmic_reg_read(p, reg, &val);
if (ret) {
debug("%s: PMIC %d register read failed\n", __func__, reg);
return -1;
}
val |= regval;
ret = pmic_reg_write(p, reg, val);
if (ret) {
debug("%s: PMIC %d register write failed\n", __func__, reg);
return -1;
}
return 0;
}
static int max77686_init(void)
{
struct pmic *p;
if (pmic_init(I2C_PMIC))
return -1;
p = pmic_get("MAX77686_PMIC");
if (!p)
return -ENODEV;
if (pmic_probe(p))
return -1;
if (pmic_reg_update(p, MAX77686_REG_PMIC_32KHZ, MAX77686_32KHCP_EN))
return -1;
if (pmic_reg_update(p, MAX77686_REG_PMIC_BBAT,
MAX77686_BBCHOSTEN | MAX77686_BBCVS_3_5V))
return -1;
/* VDD_MIF */
if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK1OUT,
MAX77686_BUCK1OUT_1V)) {
debug("%s: PMIC %d register write failed\n", __func__,
MAX77686_REG_PMIC_BUCK1OUT);
return -1;
}
if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK1CRTL,
MAX77686_BUCK1CTRL_EN))
return -1;
/* VDD_ARM */
if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK2DVS1,
MAX77686_BUCK2DVS1_1_3V)) {
debug("%s: PMIC %d register write failed\n", __func__,
MAX77686_REG_PMIC_BUCK2DVS1);
return -1;
}
if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK2CTRL1,
MAX77686_BUCK2CTRL_ON))
return -1;
/* VDD_INT */
if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK3DVS1,
MAX77686_BUCK3DVS1_1_0125V)) {
debug("%s: PMIC %d register write failed\n", __func__,
MAX77686_REG_PMIC_BUCK3DVS1);
return -1;
}
if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK3CTRL,
MAX77686_BUCK3CTRL_ON))
return -1;
/* VDD_G3D */
if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK4DVS1,
MAX77686_BUCK4DVS1_1_2V)) {
debug("%s: PMIC %d register write failed\n", __func__,
MAX77686_REG_PMIC_BUCK4DVS1);
return -1;
}
if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK4CTRL1,
MAX77686_BUCK3CTRL_ON))
return -1;
/* VDD_LDO2 */
if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO2CTRL1,
MAX77686_LD02CTRL1_1_5V | EN_LDO))
return -1;
/* VDD_LDO3 */
if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO3CTRL1,
MAX77686_LD03CTRL1_1_8V | EN_LDO))
return -1;
/* VDD_LDO5 */
if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO5CTRL1,
MAX77686_LD05CTRL1_1_8V | EN_LDO))
return -1;
/* VDD_LDO10 */
if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO10CTRL1,
MAX77686_LD10CTRL1_1_8V | EN_LDO))
return -1;
return 0;
}
#endif /* CONFIG_POWER_MAX77686 */
int exynos_power_init(void)
{
int ret = 0;
#ifdef CONFIG_POWER_MAX77686
ret = max77686_init();
if (ret)
return ret;
#endif
#ifdef CONFIG_POWER_TPS65090
/*
* The TPS65090 may not be in the device tree. If so, it is not
* an error.
*/
ret = tps65090_init();
if (ret == 0 || ret == -ENODEV)
return 0;
#endif
return ret;
}
#endif /* CONFIG_POWER */
#ifdef CONFIG_LCD
static int board_dp_bridge_setup(void)
{
const int max_tries = 10;
int num_tries, node;
/*
* TODO(sjg): Use device tree for GPIOs when exynos GPIO
* numbering patch is in mainline.
*/
debug("%s\n", __func__);
node = fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_NXP_PTN3460);
if (node < 0) {
debug("%s: No node for DP bridge in device tree\n", __func__);
return -ENODEV;
}
/* Setup the GPIOs */
/* PD is ACTIVE_LOW, and initially de-asserted */
gpio_request(EXYNOS5_GPIO_Y25, "dp_bridge_pd");
gpio_set_pull(EXYNOS5_GPIO_Y25, S5P_GPIO_PULL_NONE);
gpio_direction_output(EXYNOS5_GPIO_Y25, 1);
/* Reset is ACTIVE_LOW */
gpio_request(EXYNOS5_GPIO_X15, "dp_bridge_reset");
gpio_set_pull(EXYNOS5_GPIO_X15, S5P_GPIO_PULL_NONE);
gpio_direction_output(EXYNOS5_GPIO_X15, 0);
udelay(10);
gpio_set_value(EXYNOS5_GPIO_X15, 1);
gpio_request(EXYNOS5_GPIO_X07, "dp_bridge_hpd");
gpio_direction_input(EXYNOS5_GPIO_X07);
/*
* We need to wait for 90ms after bringing up the bridge since there
* is a phantom "high" on the HPD chip during its bootup. The phantom
* high comes within 7ms of de-asserting PD and persists for at least
* 15ms. The real high comes roughly 50ms after PD is de-asserted. The
* phantom high makes it hard for us to know when the NXP chip is up.
*/
mdelay(90);
for (num_tries = 0; num_tries < max_tries; num_tries++) {
/* Check HPD. If it's high, we're all good. */
if (gpio_get_value(EXYNOS5_GPIO_X07))
return 0;
debug("%s: eDP bridge failed to come up; try %d of %d\n",
__func__, num_tries, max_tries);
}
/* Immediately go into bridge reset if the hp line is not high */
return -ENODEV;
}
void exynos_cfg_lcd_gpio(void)
{
/* For Backlight */
gpio_request(EXYNOS5_GPIO_B20, "lcd_backlight");
gpio_cfg_pin(EXYNOS5_GPIO_B20, S5P_GPIO_OUTPUT);
gpio_set_value(EXYNOS5_GPIO_B20, 1);
/* LCD power on */
gpio_request(EXYNOS5_GPIO_X15, "lcd_power");
gpio_cfg_pin(EXYNOS5_GPIO_X15, S5P_GPIO_OUTPUT);
gpio_set_value(EXYNOS5_GPIO_X15, 1);
/* Set Hotplug detect for DP */
gpio_cfg_pin(EXYNOS5_GPIO_X07, S5P_GPIO_FUNC(0x3));
}
void exynos_set_dp_phy(unsigned int onoff)
{
set_dp_phy_ctrl(onoff);
}
void exynos_backlight_on(unsigned int on)
{
debug("%s(%u)\n", __func__, on);
if (!on)
return;
#ifdef CONFIG_POWER_TPS65090
int ret;
ret = tps65090_fet_enable(1); /* Enable FET1, backlight */
if (ret)
return;
/* T5 in the LCD timing spec (defined as > 10ms) */
mdelay(10);
/* board_dp_backlight_pwm */
gpio_direction_output(EXYNOS5_GPIO_B20, 1);
/* T6 in the LCD timing spec (defined as > 10ms) */
mdelay(10);
/* board_dp_backlight_en */
gpio_request(EXYNOS5_GPIO_X30, "board_dp_backlight_en");
gpio_direction_output(EXYNOS5_GPIO_X30, 1);
#endif
}
void exynos_lcd_power_on(void)
{
int ret;
debug("%s\n", __func__);
#ifdef CONFIG_POWER_TPS65090
/* board_dp_lcd_vdd */
tps65090_fet_enable(6); /* Enable FET6, lcd panel */
#endif
ret = board_dp_bridge_setup();
if (ret && ret != -ENODEV)
printf("LCD bridge failed to enable: %d\n", ret);
}
#endif

View File

@ -5,7 +5,3 @@
#
obj-y += smdk5420_spl.o
ifndef CONFIG_SPL_BUILD
obj-y += smdk5420.o
endif

View File

@ -1,143 +0,0 @@
/*
* Copyright (C) 2013 Samsung Electronics
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <fdtdec.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include <asm/arch/cpu.h>
#include <asm/arch/board.h>
#include <asm/arch/power.h>
#include <asm/arch/system.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/dp_info.h>
#include <asm/arch/xhci-exynos.h>
#include <power/tps65090_pmic.h>
#include <i2c.h>
#include <lcd.h>
#include <mmc.h>
#include <parade.h>
#include <spi.h>
#include <usb.h>
#include <dwc3-uboot.h>
#include <samsung-usb-phy-uboot.h>
DECLARE_GLOBAL_DATA_PTR;
int exynos_init(void)
{
return 0;
}
#ifdef CONFIG_LCD
static int has_edp_bridge(void)
{
int node;
node = fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_PARADE_PS8625);
/* No node for bridge in device tree. */
if (node <= 0)
return 0;
/* Default is with bridge ic */
return 1;
}
void exynos_lcd_power_on(void)
{
int ret;
#ifdef CONFIG_POWER_TPS65090
ret = tps65090_init();
if (ret < 0) {
printf("%s: tps65090_init() failed\n", __func__);
return;
}
tps65090_fet_enable(6);
#endif
mdelay(5);
if (has_edp_bridge())
if (parade_init(gd->fdt_blob))
printf("%s: ps8625_init() failed\n", __func__);
}
void exynos_backlight_on(unsigned int onoff)
{
#ifdef CONFIG_POWER_TPS65090
tps65090_fet_enable(1);
#endif
}
#endif
int board_get_revision(void)
{
return 0;
}
#ifdef CONFIG_USB_DWC3
static struct dwc3_device dwc3_device_data = {
.maximum_speed = USB_SPEED_SUPER,
.base = 0x12400000,
.dr_mode = USB_DR_MODE_PERIPHERAL,
.index = 0,
};
int usb_gadget_handle_interrupts(void)
{
dwc3_uboot_handle_interrupt(0);
return 0;
}
int board_usb_init(int index, enum usb_init_type init)
{
struct exynos_usb3_phy *phy = (struct exynos_usb3_phy *)
samsung_get_base_usb3_phy();
if (!phy) {
error("usb3 phy not supported");
return -ENODEV;
}
set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN);
exynos5_usb3_phy_init(phy);
return dwc3_uboot_init(&dwc3_device_data);
}
#endif
#ifdef CONFIG_SET_DFU_ALT_INFO
char *get_dfu_alt_system(char *interface, char *devstr)
{
return getenv("dfu_alt_system");
}
char *get_dfu_alt_boot(char *interface, char *devstr)
{
struct mmc *mmc;
char *alt_boot;
int dev_num;
dev_num = simple_strtoul(devstr, NULL, 10);
mmc = find_mmc_device(dev_num);
if (!mmc)
return NULL;
if (mmc_init(mmc))
return NULL;
if (IS_SD(mmc))
alt_boot = CONFIG_DFU_ALT_BOOT_SD;
else
alt_boot = CONFIG_DFU_ALT_BOOT_EMMC;
return alt_boot;
}
#endif

View File

@ -241,7 +241,8 @@ static int do_value(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
value = simple_strtoul(argv[1], NULL, 0);
if ((value < uc_pdata->min_uV || value > uc_pdata->max_uV) && !force) {
printf("Value exceeds regulator constraint limits\n");
printf("Value exceeds regulator constraint limits %d..%d uV\n",
uc_pdata->min_uV, uc_pdata->max_uV);
return CMD_RET_FAILURE;
}

View File

@ -530,13 +530,16 @@ static void do_usb_start(void)
/* try to recognize storage devices immediately */
usb_stor_curr_dev = usb_stor_scan(1);
#endif
#endif
#ifdef CONFIG_USB_HOST_ETHER
# ifdef CONFIG_DM_ETH
# error "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH"
# endif
# ifndef CONFIG_DM_USB
# error "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH"
# endif
# else
/* try to recognize ethernet devices immediately */
usb_ether_curr_dev = usb_host_eth_scan(1);
#endif
# endif
#endif
#ifdef CONFIG_USB_KEYBOARD
drv_usb_kbd_init();

View File

@ -13,3 +13,5 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_DM_I2C=y
CONFIG_DM_I2C_COMPAT=y

View File

@ -24,3 +24,7 @@ CONFIG_FRAMEBUFFER_VESA_MODE_11A=y
CONFIG_DM_RTC=y
CONFIG_USE_PRIVATE_LIBGCC=y
CONFIG_SYS_VSNPRINTF=y
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_NS16550=y
CONFIG_DEBUG_UART_BASE=0x3f8
CONFIG_DEBUG_UART_CLOCK=1843200

View File

@ -7,3 +7,9 @@ CONFIG_DEFAULT_DEVICE_TREE="exynos5422-odroidxu3"
# CONFIG_CMD_SETEXPR is not set
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_CMD_NET=y
CONFIG_DM_I2C=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_DM_PMIC=y
CONFIG_DM_REGULATOR=y
CONFIG_VIDEO_BRIDGE=y

View File

@ -12,3 +12,22 @@ CONFIG_CROS_EC_SPI=y
CONFIG_CROS_EC_KEYB=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_I2C_MUX=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_SOUND=y
CONFIG_I2S=y
CONFIG_I2S_SAMSUNG=y
CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_DM_I2C=y
CONFIG_DM_PMIC=y
CONFIG_DM_REGULATOR=y
CONFIG_PMIC_TPS65090=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
CONFIG_ERRNO_STR=y
CONFIG_VIDEO_BRIDGE=y
CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y

View File

@ -12,3 +12,22 @@ CONFIG_CROS_EC_SPI=y
CONFIG_CROS_EC_KEYB=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_I2C_MUX=y
CONFIG_I2C_CROS_EC_TUNNEL=y
CONFIG_SOUND=y
CONFIG_I2S=y
CONFIG_I2S_SAMSUNG=y
CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_DM_I2C=y
CONFIG_DM_PMIC=y
CONFIG_DM_REGULATOR=y
CONFIG_PMIC_TPS65090=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
CONFIG_ERRNO_STR=y
CONFIG_VIDEO_BRIDGE=y
CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y

View File

@ -52,3 +52,5 @@ CONFIG_DM_MMC=y
CONFIG_LED=y
CONFIG_LED_GPIO=y
CONFIG_SYSCON=y
CONFIG_REGMAP=y
CONFIG_DEVRES=y

View File

@ -14,3 +14,13 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_DM_I2C=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_DM_PMIC=y
CONFIG_DM_REGULATOR=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
CONFIG_ERRNO_STR=y
CONFIG_DM_PMIC_MAX77686=y
CONFIG_DM_REGULATOR_MAX77686=y
CONFIG_VIDEO_BRIDGE=y

View File

@ -8,3 +8,9 @@ CONFIG_SPL=y
CONFIG_SPI_FLASH=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_CMD_NET=y
CONFIG_DM_I2C=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_DM_PMIC=y
CONFIG_DM_REGULATOR=y
CONFIG_VIDEO_BRIDGE=y

View File

@ -18,3 +18,26 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_DM_I2C=y
CONFIG_DM_PMIC=y
CONFIG_DM_REGULATOR=y
CONFIG_PMIC_TPS65090=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
CONFIG_I2C_MUX=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
CONFIG_ERRNO_STR=y
CONFIG_DM_PMIC_MAX77686=y
CONFIG_DM_REGULATOR_MAX77686=y
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_S5P=y
CONFIG_DEBUG_UART_CLOCK=100000000
CONFIG_DEBUG_UART_BASE=0x12c30000
CONFIG_I2C_CROS_EC_LDO=y
CONFIG_PMIC_S5M8767=y
CONFIG_REGULATOR_S5M8767=y
CONFIG_VIDEO_BRIDGE=y
CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y
CONFIG_VIDEO_BRIDGE_NXP_PTN3460=y

42
configs/spring_defconfig Normal file
View File

@ -0,0 +1,42 @@
CONFIG_ARM=y
CONFIG_ARCH_EXYNOS=y
CONFIG_TARGET_SPRING=y
CONFIG_DEFAULT_DEVICE_TREE="exynos5250-spring"
CONFIG_SPL=y
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_SOUND=y
CONFIG_SPI_FLASH=y
CONFIG_CMD_CROS_EC=y
CONFIG_CROS_EC=y
CONFIG_CROS_EC_I2C=y
CONFIG_CROS_EC_KEYB=y
CONFIG_SOUND=y
CONFIG_I2S=y
CONFIG_I2S_SAMSUNG=y
CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_DM_I2C=y
CONFIG_DM_PMIC=y
CONFIG_DM_REGULATOR=y
CONFIG_PMIC_TPS65090=y
CONFIG_REGULATOR_TPS65090=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
CONFIG_I2C_MUX=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
CONFIG_ERRNO_STR=y
CONFIG_DM_PMIC_MAX77686=y
CONFIG_DM_REGULATOR_MAX77686=y
CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_S5P=y
CONFIG_DEBUG_UART_CLOCK=100000000
CONFIG_DEBUG_UART_BASE=0x12c30000
CONFIG_I2C_CROS_EC_LDO=y
CONFIG_PMIC_S5M8767=y
CONFIG_REGULATOR_S5M8767=y
CONFIG_VIDEO_BRIDGE=y
CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y

60
doc/README.i2c Normal file
View File

@ -0,0 +1,60 @@
I2C Bus Arbitration
===================
While I2C supports multi-master buses this is difficult to get right.
The implementation on the master side in software is quite complex.
Clock-stretching and the arbitrary time that an I2C transaction can take
make it difficult to share the bus fairly in the face of high traffic.
When one or more masters can be reset independently part-way through a
transaction it is hard to know the state of the bus.
U-Boot provides a scheme based on two 'claim' GPIOs, one driven by the
AP (Application Processor, meaning the main CPU) and one driven by the EC
(Embedded Controller, a small CPU aimed at handling system tasks). With
these they can communicate and reliably share the bus. This scheme has
minimal overhead and involves very little code. The scheme can survive
reboots by either side without difficulty.
Since U-Boot runs on the AP, the terminology used is 'our' claim GPIO,
meaning the AP's, and 'their' claim GPIO, meaning the EC's. This terminology
is used by the device tree bindings in Linux also.
The driver is implemented as an I2C mux, as it is in Linux. See
i2c-arb-gpio-challenge for the implementation.
GPIO lines are shared between the AP and EC to manage the bus. The AP and EC
each have a 'bus claim' line, which is an output that the other can see.
- AP_CLAIM: output from AP, signalling to the EC that the AP wants the bus
- EC_CLAIM: output from EC, signalling to the AP that the EC wants the bus
The basic algorithm is to assert your line when you want the bus, then make
sure that the other side doesn't want it also. A detailed explanation is best
done with an example.
Let's say the AP wants to claim the bus. It:
1. Asserts AP_CLAIM
2. Waits a little bit for the other side to notice (slew time)
3. Checks EC_CLAIM. If this is not asserted, then the AP has the bus, and we
are done
4. Otherwise, wait for a few milliseconds (retry time) and see if EC_CLAIM is
released
5. If not, back off, release the claim and wait for a few more milliseconds
(retry time again)
6. Go back to 1 if things don't look wedged (wait time has expired)
7. Panic. The other side is hung with the CLAIM line set.
The same algorithm applies on the EC.
To release the bus, just de-assert the claim line.
Typical delays are:
- slew time 10 us
- retry time 3 ms
- wait time - 50ms
In general the traffic is fairly light, and in particular the EC wants access
to the bus quite rarely (maybe every 10s or 30s to check the battery). This
scheme works very nicely with very low contention. There is only a 10 us
wait for access to the bus assuming that the other side isn't using it.

View File

@ -0,0 +1,60 @@
Common i2c bus multiplexer/switch properties.
An i2c bus multiplexer/switch will have several child busses that are
numbered uniquely in a device dependent manner. The nodes for an i2c bus
multiplexer/switch will have one child node for each child
bus.
Required properties:
- #address-cells = <1>;
- #size-cells = <0>;
Required properties for child nodes:
- #address-cells = <1>;
- #size-cells = <0>;
- reg : The sub-bus number.
Optional properties for child nodes:
- Other properties specific to the multiplexer/switch hardware.
- Child nodes conforming to i2c bus binding
Example :
/*
An NXP pca9548 8 channel I2C multiplexer at address 0x70
with two NXP pca8574 GPIO expanders attached, one each to
ports 3 and 4.
*/
mux@70 {
compatible = "nxp,pca9548";
reg = <0x70>;
#address-cells = <1>;
#size-cells = <0>;
i2c@3 {
#address-cells = <1>;
#size-cells = <0>;
reg = <3>;
gpio1: gpio@38 {
compatible = "nxp,pca8574";
reg = <0x38>;
#gpio-cells = <2>;
gpio-controller;
};
};
i2c@4 {
#address-cells = <1>;
#size-cells = <0>;
reg = <4>;
gpio2: gpio@38 {
compatible = "nxp,pca8574";
reg = <0x38>;
#gpio-cells = <2>;
gpio-controller;
};
};
};

View File

@ -0,0 +1,33 @@
ps8622-bridge bindings
Required properties:
- compatible: "parade,ps8622" or "parade,ps8625"
- reg: first i2c address of the bridge
- sleep-gpios: OF device-tree gpio specification for PD_ pin.
- reset-gpios: OF device-tree gpio specification for RST_ pin.
- parade,regs: List of 3-byte registers tuples to write:
<I2C chip address offset> <register> <value>
Optional properties:
- lane-count: number of DP lanes to use
- use-external-pwm: backlight will be controlled by an external PWM
- video interfaces: Device node can contain video interface port
nodes for panel according to [1].
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
Example:
lvds-bridge@48 {
compatible = "parade,ps8622";
reg = <0x48>;
sleep-gpios = <&gpc3 6 1 0 0>;
reset-gpios = <&gpc3 1 1 0 0>;
lane-count = <1>;
ports {
port@0 {
bridge_out: endpoint {
remote-endpoint = <&panel_in>;
};
};
};
};

View File

@ -59,3 +59,46 @@ config DM_SEQ_ALIAS
Most boards will have a '/aliases' node containing the path to
numbered devices (e.g. serial0 = &serial0). This feature can be
disabled if it is not required, to save code space in SPL.
config REGMAP
bool "Support register maps"
depends on DM
help
Hardware peripherals tend to have one or more sets of registers
which can be accessed to control the hardware. A register map
models this with a simple read/write interface. It can in principle
support any bus type (I2C, SPI) but so far this only supports
direct memory access.
config SYSCON
bool "Support system controllers"
depends on REGMAP
help
Many SoCs have a number of system controllers which are dealt with
as a group by a single driver. Some common functionality is provided
by this uclass, including accessing registers via regmap and
assigning a unique number to each.
config DEVRES
bool "Managed device resources"
depends on DM
help
This option enables the Managed device resources core support.
Device resources managed by the devres framework are automatically
released whether initialization fails half-way or the device gets
detached.
If this option is disabled, devres functions fall back to
non-managed variants. For example, devres_alloc() to kzalloc(),
devm_kmalloc() to kmalloc(), etc.
config DEBUG_DEVRES
bool "Managed device resources debugging functions"
depends on DEVRES
help
If this option is enabled, devres debug messages are printed.
Also, a function is available to dump a list of device resources.
Select this if you are having a problem with devres or want to
debug resource management for a managed device.
If you are unsure about this, Say N here.

View File

@ -5,10 +5,11 @@
#
obj-y += device.o lists.o root.o uclass.o util.o
obj-$(CONFIG_DEVRES) += devres.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_OF_CONTROL) += simple-bus.o
endif
obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o
obj-$(CONFIG_DM) += dump.o
obj-$(CONFIG_OF_CONTROL) += regmap.o
obj-$(CONFIG_OF_CONTROL) += syscon-uclass.o
obj-$(CONFIG_REGMAP) += regmap.o
obj-$(CONFIG_SYSCON) += syscon-uclass.o

View File

@ -61,6 +61,9 @@ int device_unbind(struct udevice *dev)
if (dev->flags & DM_FLAG_ACTIVATED)
return -EINVAL;
if (!(dev->flags & DM_FLAG_BOUND))
return -EINVAL;
drv = dev->driver;
assert(drv);
@ -92,6 +95,9 @@ int device_unbind(struct udevice *dev)
if (dev->parent)
list_del(&dev->sibling_node);
devres_release_all(dev);
free(dev);
return 0;
@ -125,6 +131,8 @@ void device_free(struct udevice *dev)
dev->parent_priv = NULL;
}
}
devres_release_probe(dev);
}
int device_remove(struct udevice *dev)

View File

@ -47,6 +47,9 @@ int device_bind(struct udevice *parent, const struct driver *drv,
INIT_LIST_HEAD(&dev->sibling_node);
INIT_LIST_HEAD(&dev->child_head);
INIT_LIST_HEAD(&dev->uclass_node);
#ifdef CONFIG_DEVRES
INIT_LIST_HEAD(&dev->devres_head);
#endif
dev->platdata = platdata;
dev->name = name;
dev->of_offset = of_offset;
@ -132,6 +135,8 @@ int device_bind(struct udevice *parent, const struct driver *drv,
dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
*devp = dev;
dev->flags |= DM_FLAG_BOUND;
return 0;
fail_child_post_bind:
@ -168,6 +173,8 @@ fail_alloc2:
dev->platdata = NULL;
}
fail_alloc1:
devres_release_all(dev);
free(dev);
return ret;
@ -552,17 +559,22 @@ const char *dev_get_uclass_name(struct udevice *dev)
return dev->uclass->uc_drv->name;
}
fdt_addr_t dev_get_addr(struct udevice *dev)
{
#ifdef CONFIG_OF_CONTROL
fdt_addr_t dev_get_addr(struct udevice *dev)
{
return fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
}
fdt_addr_t addr;
addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
if (addr != FDT_ADDR_T_NONE) {
if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS)
addr = simple_bus_translate(dev->parent, addr);
}
return addr;
#else
fdt_addr_t dev_get_addr(struct udevice *dev)
{
return FDT_ADDR_T_NONE;
}
#endif
}
bool device_has_children(struct udevice *dev)
{
@ -591,3 +603,13 @@ bool device_is_last_sibling(struct udevice *dev)
return false;
return list_is_last(&dev->sibling_node, &parent->child_head);
}
int device_set_name(struct udevice *dev, const char *name)
{
name = strdup(name);
if (!name)
return -ENOMEM;
dev->name = name;
return 0;
}

259
drivers/core/devres.c Normal file
View File

@ -0,0 +1,259 @@
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
*
* Based on the original work in Linux by
* Copyright (c) 2006 SUSE Linux Products GmbH
* Copyright (c) 2006 Tejun Heo <teheo@suse.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <dm/device.h>
#include <dm/root.h>
#include <dm/util.h>
/**
* struct devres - Bookkeeping info for managed device resource
* @entry: List to associate this structure with a device
* @release: Callback invoked when this resource is released
* @probe: Flag to show when this resource was allocated
(true = probe, false = bind)
* @name: Name of release function
* @size: Size of resource data
* @data: Resource data
*/
struct devres {
struct list_head entry;
dr_release_t release;
bool probe;
#ifdef CONFIG_DEBUG_DEVRES
const char *name;
size_t size;
#endif
unsigned long long data[];
};
#ifdef CONFIG_DEBUG_DEVRES
static void set_node_dbginfo(struct devres *dr, const char *name, size_t size)
{
dr->name = name;
dr->size = size;
}
static void devres_log(struct udevice *dev, struct devres *dr,
const char *op)
{
printf("%s: DEVRES %3s %p %s (%lu bytes)\n",
dev->name, op, dr, dr->name, (unsigned long)dr->size);
}
#else /* CONFIG_DEBUG_DEVRES */
#define set_node_dbginfo(dr, n, s) do {} while (0)
#define devres_log(dev, dr, op) do {} while (0)
#endif
#if CONFIG_DEBUG_DEVRES
void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
const char *name)
#else
void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
#endif
{
size_t tot_size = sizeof(struct devres) + size;
struct devres *dr;
dr = kmalloc(tot_size, gfp);
if (unlikely(!dr))
return NULL;
INIT_LIST_HEAD(&dr->entry);
dr->release = release;
set_node_dbginfo(dr, name, size);
return dr->data;
}
void devres_free(void *res)
{
if (res) {
struct devres *dr = container_of(res, struct devres, data);
BUG_ON(!list_empty(&dr->entry));
kfree(dr);
}
}
void devres_add(struct udevice *dev, void *res)
{
struct devres *dr = container_of(res, struct devres, data);
devres_log(dev, dr, "ADD");
BUG_ON(!list_empty(&dr->entry));
dr->probe = dev->flags & DM_FLAG_BOUND ? true : false;
list_add_tail(&dr->entry, &dev->devres_head);
}
void *devres_find(struct udevice *dev, dr_release_t release,
dr_match_t match, void *match_data)
{
struct devres *dr;
list_for_each_entry_reverse(dr, &dev->devres_head, entry) {
if (dr->release != release)
continue;
if (match && !match(dev, dr->data, match_data))
continue;
return dr->data;
}
return NULL;
}
void *devres_get(struct udevice *dev, void *new_res,
dr_match_t match, void *match_data)
{
struct devres *new_dr = container_of(new_res, struct devres, data);
void *res;
res = devres_find(dev, new_dr->release, match, match_data);
if (!res) {
devres_add(dev, new_res);
res = new_res;
new_res = NULL;
}
devres_free(new_res);
return res;
}
void *devres_remove(struct udevice *dev, dr_release_t release,
dr_match_t match, void *match_data)
{
void *res;
res = devres_find(dev, release, match, match_data);
if (res) {
struct devres *dr = container_of(res, struct devres, data);
list_del_init(&dr->entry);
devres_log(dev, dr, "REM");
}
return res;
}
int devres_destroy(struct udevice *dev, dr_release_t release,
dr_match_t match, void *match_data)
{
void *res;
res = devres_remove(dev, release, match, match_data);
if (unlikely(!res))
return -ENOENT;
devres_free(res);
return 0;
}
int devres_release(struct udevice *dev, dr_release_t release,
dr_match_t match, void *match_data)
{
void *res;
res = devres_remove(dev, release, match, match_data);
if (unlikely(!res))
return -ENOENT;
(*release)(dev, res);
devres_free(res);
return 0;
}
static void release_nodes(struct udevice *dev, struct list_head *head,
bool probe_only)
{
struct devres *dr, *tmp;
list_for_each_entry_safe_reverse(dr, tmp, head, entry) {
if (probe_only && !dr->probe)
break;
devres_log(dev, dr, "REL");
dr->release(dev, dr->data);
list_del(&dr->entry);
kfree(dr);
}
}
void devres_release_probe(struct udevice *dev)
{
release_nodes(dev, &dev->devres_head, true);
}
void devres_release_all(struct udevice *dev)
{
release_nodes(dev, &dev->devres_head, false);
}
#ifdef CONFIG_DEBUG_DEVRES
static void dump_resources(struct udevice *dev, int depth)
{
struct devres *dr;
struct udevice *child;
printf("- %s\n", dev->name);
list_for_each_entry(dr, &dev->devres_head, entry)
printf(" %p (%lu byte) %s %s\n", dr,
(unsigned long)dr->size, dr->name,
dr->probe ? "PROBE" : "BIND");
list_for_each_entry(child, &dev->child_head, sibling_node)
dump_resources(child, depth + 1);
}
void dm_dump_devres(void)
{
struct udevice *root;
root = dm_root();
if (root)
dump_resources(root, 0);
}
#endif
/*
* Managed kmalloc/kfree
*/
static void devm_kmalloc_release(struct udevice *dev, void *res)
{
/* noop */
}
static int devm_kmalloc_match(struct udevice *dev, void *res, void *data)
{
return res == data;
}
void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp)
{
void *data;
data = _devres_alloc(devm_kmalloc_release, size, gfp);
if (unlikely(!data))
return NULL;
devres_add(dev, data);
return data;
}
void devm_kfree(struct udevice *dev, void *p)
{
int rc;
rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p);
WARN_ON(rc);
}

View File

@ -10,8 +10,37 @@
DECLARE_GLOBAL_DATA_PTR;
struct simple_bus_plat {
u32 base;
u32 size;
u32 target;
};
fdt_addr_t simple_bus_translate(struct udevice *dev, fdt_addr_t addr)
{
struct simple_bus_plat *plat = dev_get_uclass_platdata(dev);
if (addr >= plat->base && addr < plat->base + plat->size)
addr = (addr - plat->base) + plat->target;
return addr;
}
static int simple_bus_post_bind(struct udevice *dev)
{
u32 cell[3];
int ret;
ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "ranges",
cell, ARRAY_SIZE(cell));
if (!ret) {
struct simple_bus_plat *plat = dev_get_uclass_platdata(dev);
plat->base = cell[0];
plat->target = cell[1];
plat->size = cell[2];
}
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
@ -19,6 +48,7 @@ UCLASS_DRIVER(simple_bus) = {
.id = UCLASS_SIMPLE_BUS,
.name = "simple_bus",
.post_bind = simple_bus_post_bind,
.per_device_platdata_auto_alloc_size = sizeof(struct simple_bus_plat),
};
static const struct udevice_id generic_simple_bus_ids[] = {

View File

@ -273,6 +273,37 @@ static int uclass_find_device_by_of_offset(enum uclass_id id, int node,
return -ENODEV;
}
static int uclass_find_device_by_phandle(enum uclass_id id,
struct udevice *parent,
const char *name,
struct udevice **devp)
{
struct udevice *dev;
struct uclass *uc;
int find_phandle;
int ret;
*devp = NULL;
find_phandle = fdtdec_get_int(gd->fdt_blob, parent->of_offset, name,
-1);
if (find_phandle <= 0)
return -ENOENT;
ret = uclass_get(id, &uc);
if (ret)
return ret;
list_for_each_entry(dev, &uc->dev_head, uclass_node) {
uint phandle = fdt_get_phandle(gd->fdt_blob, dev->of_offset);
if (phandle == find_phandle) {
*devp = dev;
return 0;
}
}
return -ENODEV;
}
int uclass_get_device_tail(struct udevice *dev, int ret,
struct udevice **devp)
{
@ -338,6 +369,17 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node,
return uclass_get_device_tail(dev, ret, devp);
}
int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
const char *name, struct udevice **devp)
{
struct udevice *dev;
int ret;
*devp = NULL;
ret = uclass_find_device_by_phandle(id, parent, name, &dev);
return uclass_get_device_tail(dev, ret, devp);
}
int uclass_first_device(enum uclass_id id, struct udevice **devp)
{
struct udevice *dev;

View File

@ -250,8 +250,12 @@ int gpio_free(unsigned gpio)
static int check_reserved(struct gpio_desc *desc, const char *func)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(desc->dev);
struct gpio_dev_priv *uc_priv;
if (!dm_gpio_is_valid(desc))
return -ENOENT;
uc_priv = dev_get_uclass_priv(desc->dev);
if (!uc_priv->name[desc->offset]) {
printf("%s: %s: error: gpio %s%d not reserved\n",
desc->dev->name, func,

View File

@ -19,6 +19,30 @@ config DM_I2C_COMPAT
to convert all code for a board in a single commit. It should not
be enabled for any board in an official release.
config I2C_CROS_EC_TUNNEL
tristate "Chrome OS EC tunnel I2C bus"
depends on CROS_EC
help
This provides an I2C bus that will tunnel i2c commands through to
the other side of the Chrome OS EC to the I2C bus connected there.
This will work whatever the interface used to talk to the EC (SPI,
I2C or LPC). Some Chromebooks use this when the hardware design
does not allow direct access to the main PMIC from the AP.
config I2C_CROS_EC_LDO
bool "Provide access to LDOs on the Chrome OS EC"
depends on CROS_EC
---help---
On many Chromebooks the main PMIC is inaccessible to the AP. This is
often dealt with by using an I2C pass-through interface provided by
the EC. On some unfortunate models (e.g. Spring) the pass-through
is not available, and an LDO message is available instead. This
option enables a driver which provides very basic access to those
regulators, via the EC. We implement this as an I2C bus which
emulates just the TPS65090 messages we know about. This is done to
avoid duplicating the logic in the TPS65090 regulator driver for
enabling/disabling an LDO.
config DM_I2C_GPIO
bool "Enable Driver Model for software emulated I2C bus driver"
depends on DM_I2C && DM_GPIO
@ -73,3 +97,5 @@ config SYS_I2C_UNIPHIER_F
help
Support for UniPhier FIFO-builtin I2C controller driver.
This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs.
source "drivers/i2c/muxes/Kconfig"

View File

@ -7,6 +7,8 @@
obj-$(CONFIG_DM_I2C) += i2c-uclass.o
obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
obj-$(CONFIG_DM_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += cros_ec_tunnel.o
obj-$(CONFIG_I2C_CROS_EC_LDO) += cros_ec_ldo.o
obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
obj-$(CONFIG_I2C_MV) += mv_i2c.o
@ -37,3 +39,5 @@ obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o
obj-y += muxes/

77
drivers/i2c/cros_ec_ldo.c Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <cros_ec.h>
#include <errno.h>
#include <i2c.h>
#include <power/tps65090.h>
static int cros_ec_ldo_set_bus_speed(struct udevice *dev, unsigned int speed)
{
return 0;
}
static int cros_ec_ldo_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
bool is_read = nmsgs > 1;
int fet_id, ret;
/*
* Look for reads and writes of the LDO registers. In either case the
* first message is a write with the register number as the first byte.
*/
if (!nmsgs || !msg->len || (msg->flags & I2C_M_RD)) {
debug("%s: Invalid message\n", __func__);
goto err;
}
fet_id = msg->buf[0] - REG_FET_BASE;
if (fet_id < 1 || fet_id > MAX_FET_NUM) {
debug("%s: Invalid FET %d\n", __func__, fet_id);
goto err;
}
if (is_read) {
uint8_t state;
ret = cros_ec_get_ldo(dev->parent, fet_id, &state);
if (!ret)
msg[1].buf[0] = state ?
FET_CTRL_ENFET | FET_CTRL_PGFET : 0;
} else {
bool on = msg->buf[1] & FET_CTRL_ENFET;
ret = cros_ec_set_ldo(dev->parent, fet_id, on);
}
return ret;
err:
/* Indicate that the message is unimplemented */
return -ENOSYS;
}
static const struct dm_i2c_ops cros_ec_i2c_ops = {
.xfer = cros_ec_ldo_xfer,
.set_bus_speed = cros_ec_ldo_set_bus_speed,
};
static const struct udevice_id cros_ec_i2c_ids[] = {
{ .compatible = "google,cros-ec-ldo-tunnel" },
{ }
};
U_BOOT_DRIVER(cros_ec_ldo) = {
.name = "cros_ec_ldo_tunnel",
.id = UCLASS_I2C,
.of_match = cros_ec_i2c_ids,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.ops = &cros_ec_i2c_ops,
};

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <cros_ec.h>
#include <errno.h>
#include <i2c.h>
static int cros_ec_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
{
return 0;
}
static int cros_ec_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
return cros_ec_i2c_tunnel(dev->parent, msg, nmsgs);
}
static const struct dm_i2c_ops cros_ec_i2c_ops = {
.xfer = cros_ec_i2c_xfer,
.set_bus_speed = cros_ec_i2c_set_bus_speed,
};
static const struct udevice_id cros_ec_i2c_ids[] = {
{ .compatible = "google,cros-ec-i2c-tunnel" },
{ }
};
U_BOOT_DRIVER(cros_ec_tunnel) = {
.name = "cros_ec_tunnel",
.id = UCLASS_I2C,
.of_match = cros_ec_i2c_ids,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.ops = &cros_ec_i2c_ops,
};

View File

@ -18,6 +18,22 @@ DECLARE_GLOBAL_DATA_PTR;
#define I2C_MAX_OFFSET_LEN 4
/* Useful debugging function */
void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs)
{
int i;
for (i = 0; i < nmsgs; i++) {
struct i2c_msg *m = &msg[i];
printf(" %s %x len=%x", m->flags & I2C_M_RD ? "R" : "W",
msg->addr, msg->len);
if (!(m->flags & I2C_M_RD))
printf(": %x", m->buf[0]);
printf("\n");
}
}
/**
* i2c_setup_offset() - Set up a new message with a chip offset
*
@ -186,6 +202,17 @@ int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
}
}
int dm_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
{
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
if (!ops->xfer)
return -ENOSYS;
return ops->xfer(bus, msg, nmsgs);
}
int dm_i2c_reg_read(struct udevice *dev, uint offset)
{
uint8_t val;

17
drivers/i2c/muxes/Kconfig Normal file
View File

@ -0,0 +1,17 @@
config I2C_MUX
bool "Suport I2C multiplexers"
depends on DM_I2C
help
This enables I2C buses to be multiplexed, so that you can select
one of several buses using some sort of control mechanism. The
bus select is handled automatically when that bus is accessed,
using a suitable I2C MUX driver.
config I2C_ARB_GPIO_CHALLENGE
bool "GPIO-based I2C arbitration"
depends on I2C_MUX
help
If you say yes to this option, support will be included for an
I2C multimaster arbitration scheme using GPIOs and a challenge &
response mechanism where masters have to claim the bus by asserting
a GPIO.

View File

@ -0,0 +1,7 @@
#
# Copyright (c) 2015 Google, Inc
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
obj-$(CONFIG_I2C_MUX) += i2c-mux-uclass.o

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
struct i2c_arbitrator_priv {
struct gpio_desc ap_claim;
struct gpio_desc ec_claim;
uint slew_delay_us;
uint wait_retry_ms;
uint wait_free_ms;
};
int i2c_arbitrator_deselect(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
int ret;
debug("%s: %s\n", __func__, mux->name);
ret = dm_gpio_set_value(&priv->ap_claim, 0);
udelay(priv->slew_delay_us);
return ret;
}
int i2c_arbitrator_select(struct udevice *mux, struct udevice *bus,
uint channel)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(mux);
unsigned start;
int ret;
debug("%s: %s\n", __func__, mux->name);
/* Start a round of trying to claim the bus */
start = get_timer(0);
do {
unsigned start_retry;
int waiting = 0;
/* Indicate that we want to claim the bus */
ret = dm_gpio_set_value(&priv->ap_claim, 1);
if (ret)
goto err;
udelay(priv->slew_delay_us);
/* Wait for the EC to release it */
start_retry = get_timer(0);
while (get_timer(start_retry) < priv->wait_retry_ms) {
ret = dm_gpio_get_value(&priv->ec_claim);
if (ret < 0) {
goto err;
} else if (!ret) {
/* We got it, so return */
return 0;
}
if (!waiting)
waiting = 1;
}
/* It didn't release, so give up, wait, and try again */
ret = dm_gpio_set_value(&priv->ap_claim, 0);
if (ret)
goto err;
mdelay(priv->wait_retry_ms);
} while (get_timer(start) < priv->wait_free_ms);
/* Give up, release our claim */
printf("I2C: Could not claim bus, timeout %lu\n", get_timer(start));
ret = -ETIMEDOUT;
ret = 0;
err:
return ret;
}
static int i2c_arbitrator_probe(struct udevice *dev)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
const void *blob = gd->fdt_blob;
int node = dev->of_offset;
int ret;
debug("%s: %s\n", __func__, dev->name);
priv->slew_delay_us = fdtdec_get_int(blob, node, "slew-delay-us", 0);
priv->wait_retry_ms = fdtdec_get_int(blob, node, "wait-retry-us", 0) /
1000;
priv->wait_free_ms = fdtdec_get_int(blob, node, "wait-free-us", 0) /
1000;
ret = gpio_request_by_name(dev, "our-claim-gpio", 0, &priv->ap_claim,
GPIOD_IS_OUT);
if (ret)
goto err;
ret = gpio_request_by_name(dev, "their-claim-gpios", 0, &priv->ec_claim,
GPIOD_IS_IN);
if (ret)
goto err_ec_gpio;
return 0;
err_ec_gpio:
dm_gpio_free(dev, &priv->ap_claim);
err:
debug("%s: ret=%d\n", __func__, ret);
return ret;
}
static int i2c_arbitrator_remove(struct udevice *dev)
{
struct i2c_arbitrator_priv *priv = dev_get_priv(dev);
dm_gpio_free(dev, &priv->ap_claim);
dm_gpio_free(dev, &priv->ec_claim);
return 0;
}
static const struct i2c_mux_ops i2c_arbitrator_ops = {
.select = i2c_arbitrator_select,
.deselect = i2c_arbitrator_deselect,
};
static const struct udevice_id i2c_arbitrator_ids[] = {
{ .compatible = "i2c-arb-gpio-challenge" },
{ }
};
U_BOOT_DRIVER(i2c_arbitrator) = {
.name = "i2c_arbitrator",
.id = UCLASS_I2C_MUX,
.of_match = i2c_arbitrator_ids,
.probe = i2c_arbitrator_probe,
.remove = i2c_arbitrator_remove,
.ops = &i2c_arbitrator_ops,
.priv_auto_alloc_size = sizeof(struct i2c_arbitrator_priv),
};

View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <dm/lists.h>
#include <dm/root.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* struct i2c_mux: Information the uclass stores about an I2C mux
*
* @selected: Currently selected mux, or -1 for none
* @i2c_bus: I2C bus to use for communcation
*/
struct i2c_mux {
int selected;
struct udevice *i2c_bus;
};
/**
* struct i2c_mux_bus: Information about each bus the mux controls
*
* @channel: Channel number used to select this bus
*/
struct i2c_mux_bus {
uint channel;
};
/* Find out the mux channel number */
static int i2c_mux_child_post_bind(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
int channel;
channel = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1);
if (channel < 0)
return -EINVAL;
plat->channel = channel;
return 0;
}
/* Find the I2C buses selected by this mux */
static int i2c_mux_post_bind(struct udevice *mux)
{
const void *blob = gd->fdt_blob;
int ret;
int offset;
debug("%s: %s\n", __func__, mux->name);
/*
* There is no compatible string in the sub-nodes, so we must manually
* bind these
*/
for (offset = fdt_first_subnode(blob, mux->of_offset);
offset > 0;
offset = fdt_next_subnode(blob, offset)) {
struct udevice *dev;
const char *name;
name = fdt_get_name(blob, offset, NULL);
ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv", name,
offset, &dev);
debug(" - bind ret=%d, %s\n", ret, dev ? dev->name : NULL);
if (ret)
return ret;
}
return 0;
}
/* Set up the mux ready for use */
static int i2c_mux_post_probe(struct udevice *mux)
{
struct i2c_mux *priv = dev_get_uclass_priv(mux);
int ret;
debug("%s: %s\n", __func__, mux->name);
priv->selected = -1;
ret = uclass_get_device_by_phandle(UCLASS_I2C, mux, "i2c-parent",
&priv->i2c_bus);
if (ret)
return ret;
debug("%s: bus=%p/%s\n", __func__, priv->i2c_bus, priv->i2c_bus->name);
return 0;
}
int i2c_mux_select(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
struct udevice *mux = dev->parent;
struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
if (!ops->select)
return -ENOSYS;
return ops->select(mux, dev, plat->channel);
}
int i2c_mux_deselect(struct udevice *dev)
{
struct i2c_mux_bus *plat = dev_get_parent_platdata(dev);
struct udevice *mux = dev->parent;
struct i2c_mux_ops *ops = i2c_mux_get_ops(mux);
if (!ops->deselect)
return -ENOSYS;
return ops->deselect(mux, dev, plat->channel);
}
static int i2c_mux_bus_set_bus_speed(struct udevice *dev, unsigned int speed)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
int ret, ret2;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = dm_i2c_set_bus_speed(priv->i2c_bus, speed);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static int i2c_mux_bus_probe(struct udevice *dev, uint chip_addr,
uint chip_flags)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
int ret, ret2;
debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
if (!ops->probe_chip)
return -ENOSYS;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = ops->probe_chip(priv->i2c_bus, chip_addr, chip_flags);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static int i2c_mux_bus_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct udevice *mux = dev->parent;
struct i2c_mux *priv = dev_get_uclass_priv(mux);
struct dm_i2c_ops *ops = i2c_get_ops(priv->i2c_bus);
int ret, ret2;
debug("%s: %s, bus %s\n", __func__, dev->name, priv->i2c_bus->name);
if (!ops->xfer)
return -ENOSYS;
ret = i2c_mux_select(dev);
if (ret)
return ret;
ret = ops->xfer(priv->i2c_bus, msg, nmsgs);
ret2 = i2c_mux_deselect(dev);
return ret ? ret : ret2;
}
static const struct dm_i2c_ops i2c_mux_bus_ops = {
.xfer = i2c_mux_bus_xfer,
.probe_chip = i2c_mux_bus_probe,
.set_bus_speed = i2c_mux_bus_set_bus_speed,
};
U_BOOT_DRIVER(i2c_mux_bus) = {
.name = "i2c_mux_bus_drv",
.id = UCLASS_I2C,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.ops = &i2c_mux_bus_ops,
};
UCLASS_DRIVER(i2c_mux) = {
.id = UCLASS_I2C_MUX,
.name = "i2c_mux",
.post_bind = i2c_mux_post_bind,
.post_probe = i2c_mux_post_probe,
.per_device_auto_alloc_size = sizeof(struct i2c_mux),
.per_child_platdata_auto_alloc_size = sizeof(struct i2c_mux_bus),
.child_post_bind = i2c_mux_child_post_bind,
};

View File

@ -258,9 +258,9 @@ static int hsi2c_wait_for_trx(struct exynos5_hsi2c *i2c)
return I2C_NOK_TOUT;
}
static void ReadWriteByte(struct s3c24x0_i2c *i2c)
static void read_write_byte(struct s3c24x0_i2c *i2c)
{
writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
clrbits_le32(&i2c->iiccon, I2CCON_IRPND);
}
#ifdef CONFIG_SYS_I2C
@ -794,7 +794,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
if (addr && addr_len) {
while ((i < addr_len) && (result == I2C_OK)) {
writel(addr[i++], &i2c->iicds);
ReadWriteByte(i2c);
read_write_byte(i2c);
result = WaitForXfer(i2c);
}
i = 0;
@ -806,7 +806,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
case I2C_WRITE:
while ((i < data_len) && (result == I2C_OK)) {
writel(data[i++], &i2c->iicds);
ReadWriteByte(i2c);
read_write_byte(i2c);
result = WaitForXfer(i2c);
}
break;
@ -822,7 +822,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
/* Generate a re-START. */
writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP,
&i2c->iicstat);
ReadWriteByte(i2c);
read_write_byte(i2c);
result = WaitForXfer(i2c);
if (result != I2C_OK)
@ -835,7 +835,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
writel(readl(&i2c->iiccon)
& ~I2CCON_ACKGEN,
&i2c->iiccon);
ReadWriteByte(i2c);
read_write_byte(i2c);
result = WaitForXfer(i2c);
data[i++] = readl(&i2c->iicds);
}
@ -852,7 +852,7 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
bailout:
/* Send STOP. */
writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
ReadWriteByte(i2c);
read_write_byte(i2c);
return result;
}
@ -1284,62 +1284,106 @@ U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
#endif /* CONFIG_SYS_I2C */
#ifdef CONFIG_DM_I2C
static int i2c_write_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
uchar *buffer, int len, bool end_with_repeated_start)
static int exynos_hs_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
int ret;
if (i2c_bus->is_highspeed) {
ret = hsi2c_write(i2c_bus->hsregs, chip, 0, 0,
buffer, len, true);
if (ret)
for (; nmsgs > 0; nmsgs--, msg++) {
if (msg->flags & I2C_M_RD) {
ret = hsi2c_read(hsregs, msg->addr, 0, 0, msg->buf,
msg->len);
} else {
ret = hsi2c_write(hsregs, msg->addr, 0, 0, msg->buf,
msg->len, true);
}
if (ret) {
exynos5_i2c_reset(i2c_bus);
} else {
ret = i2c_transfer(i2c_bus->regs, I2C_WRITE,
chip << 1, 0, 0, buffer, len);
return -EREMOTEIO;
}
}
return ret != I2C_OK;
return 0;
}
static int i2c_read_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
uchar *buffer, int len)
static int s3c24x0_do_msg(struct s3c24x0_i2c_bus *i2c_bus, struct i2c_msg *msg,
int seq)
{
int ret;
struct s3c24x0_i2c *i2c = i2c_bus->regs;
bool is_read = msg->flags & I2C_M_RD;
uint status;
uint addr;
int ret, i;
if (i2c_bus->is_highspeed) {
ret = hsi2c_read(i2c_bus->hsregs, chip, 0, 0, buffer, len);
if (ret)
exynos5_i2c_reset(i2c_bus);
if (!seq)
setbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
/* Get the slave chip address going */
addr = msg->addr << 1;
writel(addr, &i2c->iicds);
status = I2C_TXRX_ENA | I2C_START_STOP;
if (is_read)
status |= I2C_MODE_MR;
else
status |= I2C_MODE_MT;
writel(status, &i2c->iicstat);
if (seq)
read_write_byte(i2c);
/* Wait for chip address to transmit */
ret = WaitForXfer(i2c);
if (ret)
goto err;
if (is_read) {
for (i = 0; !ret && i < msg->len; i++) {
/* disable ACK for final READ */
if (i == msg->len - 1)
clrbits_le32(&i2c->iiccon, I2CCON_ACKGEN);
read_write_byte(i2c);
ret = WaitForXfer(i2c);
msg->buf[i] = readl(&i2c->iicds);
}
if (ret == I2C_NACK)
ret = I2C_OK; /* Normal terminated read */
} else {
ret = i2c_transfer(i2c_bus->regs, I2C_READ,
chip << 1, 0, 0, buffer, len);
for (i = 0; !ret && i < msg->len; i++) {
writel(msg->buf[i], &i2c->iicds);
read_write_byte(i2c);
ret = WaitForXfer(i2c);
}
}
return ret != I2C_OK;
err:
return ret;
}
static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
int ret;
struct s3c24x0_i2c *i2c = i2c_bus->regs;
ulong start_time;
int ret, i;
for (; nmsgs > 0; nmsgs--, msg++) {
bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
if (msg->flags & I2C_M_RD) {
ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
msg->len);
} else {
ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
msg->len, next_is_read);
start_time = get_timer(0);
while (readl(&i2c->iicstat) & I2CSTAT_BSY) {
if (get_timer(start_time) > I2C_TIMEOUT_MS) {
debug("Timeout\n");
return -ETIMEDOUT;
}
if (ret)
return -EREMOTEIO;
}
return 0;
for (ret = 0, i = 0; !ret && i < nmsgs; i++)
ret = s3c24x0_do_msg(i2c_bus, &msg[i], i);
/* Send STOP */
writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
read_write_byte(i2c);
return ret ? -EREMOTEIO : 0;
}
static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
@ -1364,8 +1408,7 @@ static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
i2c_bus->id = pinmux_decode_periph_id(blob, node);
i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
"clock-frequency",
CONFIG_SYS_I2C_S3C24X0_SPEED);
"clock-frequency", 100000);
i2c_bus->node = node;
i2c_bus->bus_num = dev->seq;
@ -1384,7 +1427,6 @@ static const struct dm_i2c_ops s3c_i2c_ops = {
static const struct udevice_id s3c_i2c_ids[] = {
{ .compatible = "samsung,s3c2440-i2c", .data = EXYNOS_I2C_STD },
{ .compatible = "samsung,exynos5-hsi2c", .data = EXYNOS_I2C_HS },
{ }
};
@ -1397,4 +1439,29 @@ U_BOOT_DRIVER(i2c_s3c) = {
.priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
.ops = &s3c_i2c_ops,
};
/*
* TODO(sjg@chromium.org): Move this to a separate file when everything uses
* driver model
*/
static const struct dm_i2c_ops exynos_hs_i2c_ops = {
.xfer = exynos_hs_i2c_xfer,
.probe_chip = s3c24x0_i2c_probe,
.set_bus_speed = s3c24x0_i2c_set_bus_speed,
};
static const struct udevice_id exynos_hs_i2c_ids[] = {
{ .compatible = "samsung,exynos5-hsi2c", .data = EXYNOS_I2C_HS },
{ }
};
U_BOOT_DRIVER(hs_i2c) = {
.name = "i2c_s3c_hs",
.id = UCLASS_I2C,
.of_match = exynos_hs_i2c_ids,
.ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
.ops = &exynos_hs_i2c_ops,
};
#endif /* CONFIG_DM_I2C */

View File

@ -26,6 +26,7 @@
#include <asm/io.h>
#include <asm-generic/gpio.h>
#include <dm/device-internal.h>
#include <dm/root.h>
#include <dm/uclass-internal.h>
#ifdef DEBUG_TRACE
@ -930,31 +931,32 @@ int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block)
return 0;
}
int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state)
int cros_ec_set_ldo(struct udevice *dev, uint8_t index, uint8_t state)
{
struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
struct ec_params_ldo_set params;
params.index = index;
params.state = state;
if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0,
&params, sizeof(params),
NULL, 0))
if (ec_command_inptr(cdev, EC_CMD_LDO_SET, 0, &params, sizeof(params),
NULL, 0))
return -1;
return 0;
}
int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state)
int cros_ec_get_ldo(struct udevice *dev, uint8_t index, uint8_t *state)
{
struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
struct ec_params_ldo_get params;
struct ec_response_ldo_get *resp;
params.index = index;
if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0,
&params, sizeof(params),
(uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp))
if (ec_command_inptr(cdev, EC_CMD_LDO_GET, 0, &params, sizeof(params),
(uint8_t **)&resp, sizeof(*resp)) !=
sizeof(*resp))
return -1;
*state = resp->state;
@ -1053,9 +1055,9 @@ int cros_ec_decode_ec_flash(const void *blob, int node,
return 0;
}
int cros_ec_i2c_xfer(struct cros_ec_dev *dev, uchar chip, uint addr,
int alen, uchar *buffer, int len, int is_read)
int cros_ec_i2c_tunnel(struct udevice *dev, struct i2c_msg *in, int nmsgs)
{
struct cros_ec_dev *cdev = dev_get_uclass_priv(dev);
union {
struct ec_params_i2c_passthru p;
uint8_t outbuf[EC_PROTO2_MAX_PARAM_SIZE];
@ -1066,53 +1068,46 @@ int cros_ec_i2c_xfer(struct cros_ec_dev *dev, uchar chip, uint addr,
} response;
struct ec_params_i2c_passthru *p = &params.p;
struct ec_response_i2c_passthru *r = &response.r;
struct ec_params_i2c_passthru_msg *msg = p->msg;
uint8_t *pdata;
int read_len, write_len;
struct ec_params_i2c_passthru_msg *msg;
uint8_t *pdata, *read_ptr = NULL;
int read_len;
int size;
int rv;
int i;
p->port = 0;
if (alen != 1) {
printf("Unsupported address length %d\n", alen);
return -1;
}
if (is_read) {
read_len = len;
write_len = alen;
p->num_msgs = 2;
} else {
read_len = 0;
write_len = alen + len;
p->num_msgs = 1;
}
p->num_msgs = nmsgs;
size = sizeof(*p) + p->num_msgs * sizeof(*msg);
if (size + write_len > sizeof(params)) {
puts("Params too large for buffer\n");
return -1;
}
if (sizeof(*r) + read_len > sizeof(response)) {
puts("Read length too big for buffer\n");
return -1;
}
/* Create a message to write the register address and optional data */
pdata = (uint8_t *)p + size;
msg->addr_flags = chip;
msg->len = write_len;
pdata[0] = addr;
if (!is_read)
memcpy(pdata + 1, buffer, len);
msg++;
if (read_len) {
msg->addr_flags = chip | EC_I2C_FLAG_READ;
msg->len = read_len;
read_len = 0;
for (i = 0, msg = p->msg; i < nmsgs; i++, msg++, in++) {
bool is_read = in->flags & I2C_M_RD;
msg->addr_flags = in->addr;
msg->len = in->len;
if (is_read) {
msg->addr_flags |= EC_I2C_FLAG_READ;
read_len += in->len;
read_ptr = in->buf;
if (sizeof(*r) + read_len > sizeof(response)) {
puts("Read length too big for buffer\n");
return -1;
}
} else {
if (pdata - (uint8_t *)p + in->len > sizeof(params)) {
puts("Params too large for buffer\n");
return -1;
}
memcpy(pdata, in->buf, in->len);
pdata += in->len;
}
}
rv = ec_command(dev, EC_CMD_I2C_PASSTHRU, 0, p, size + write_len,
rv = ec_command(cdev, EC_CMD_I2C_PASSTHRU, 0, p, pdata - (uint8_t *)p,
r, sizeof(*r) + read_len);
if (rv < 0)
return rv;
@ -1128,8 +1123,9 @@ int cros_ec_i2c_xfer(struct cros_ec_dev *dev, uchar chip, uint addr,
return -1;
}
/* We only support a single read message for each transfer */
if (read_len)
memcpy(buffer, r->data, read_len);
memcpy(read_ptr, r->data, read_len);
return 0;
}
@ -1189,187 +1185,6 @@ static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc,
return 0;
}
/**
* get_alen() - Small parser helper function to get address length
*
* Returns the address length.
*/
static uint get_alen(char *arg)
{
int j;
int alen;
alen = 1;
for (j = 0; j < 8; j++) {
if (arg[j] == '.') {
alen = arg[j+1] - '0';
break;
} else if (arg[j] == '\0') {
break;
}
}
return alen;
}
#define DISP_LINE_LEN 16
/*
* TODO(sjg@chromium.org): This code copied almost verbatim from cmd_i2c.c
* so we can remove it later.
*/
static int cros_ec_i2c_md(struct cros_ec_dev *dev, int flag, int argc,
char * const argv[])
{
u_char chip;
uint addr, alen, length = 0x10;
int j, nbytes, linebytes;
if (argc < 2)
return CMD_RET_USAGE;
if (1 || (flag & CMD_FLAG_REPEAT) == 0) {
/*
* New command specified.
*/
/*
* I2C chip address
*/
chip = simple_strtoul(argv[0], NULL, 16);
/*
* I2C data address within the chip. This can be 1 or
* 2 bytes long. Some day it might be 3 bytes long :-).
*/
addr = simple_strtoul(argv[1], NULL, 16);
alen = get_alen(argv[1]);
if (alen > 3)
return CMD_RET_USAGE;
/*
* If another parameter, it is the length to display.
* Length is the number of objects, not number of bytes.
*/
if (argc > 2)
length = simple_strtoul(argv[2], NULL, 16);
}
/*
* Print the lines.
*
* We buffer all read data, so we can make sure data is read only
* once.
*/
nbytes = length;
do {
unsigned char linebuf[DISP_LINE_LEN];
unsigned char *cp;
linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
if (cros_ec_i2c_xfer(dev, chip, addr, alen, linebuf, linebytes,
1))
puts("Error reading the chip.\n");
else {
printf("%04x:", addr);
cp = linebuf;
for (j = 0; j < linebytes; j++) {
printf(" %02x", *cp++);
addr++;
}
puts(" ");
cp = linebuf;
for (j = 0; j < linebytes; j++) {
if ((*cp < 0x20) || (*cp > 0x7e))
puts(".");
else
printf("%c", *cp);
cp++;
}
putc('\n');
}
nbytes -= linebytes;
} while (nbytes > 0);
return 0;
}
static int cros_ec_i2c_mw(struct cros_ec_dev *dev, int flag, int argc,
char * const argv[])
{
uchar chip;
ulong addr;
uint alen;
uchar byte;
int count;
if ((argc < 3) || (argc > 4))
return CMD_RET_USAGE;
/*
* Chip is always specified.
*/
chip = simple_strtoul(argv[0], NULL, 16);
/*
* Address is always specified.
*/
addr = simple_strtoul(argv[1], NULL, 16);
alen = get_alen(argv[1]);
if (alen > 3)
return CMD_RET_USAGE;
/*
* Value to write is always specified.
*/
byte = simple_strtoul(argv[2], NULL, 16);
/*
* Optional count
*/
if (argc == 4)
count = simple_strtoul(argv[3], NULL, 16);
else
count = 1;
while (count-- > 0) {
if (cros_ec_i2c_xfer(dev, chip, addr++, alen, &byte, 1, 0))
puts("Error writing the chip.\n");
/*
* Wait for the write to complete. The write can take
* up to 10mSec (we allow a little more time).
*/
/*
* No write delay with FRAM devices.
*/
#if !defined(CONFIG_SYS_I2C_FRAM)
udelay(11000);
#endif
}
return 0;
}
/* Temporary code until we have driver model and can use the i2c command */
static int cros_ec_i2c_passthrough(struct cros_ec_dev *dev, int flag,
int argc, char * const argv[])
{
const char *cmd;
if (argc < 1)
return CMD_RET_USAGE;
cmd = *argv++;
argc--;
if (0 == strcmp("md", cmd))
cros_ec_i2c_md(dev, flag, argc, argv);
else if (0 == strcmp("mw", cmd))
cros_ec_i2c_mw(dev, flag, argc, argv);
else
return CMD_RET_USAGE;
return 0;
}
static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct cros_ec_dev *dev;
@ -1605,9 +1420,9 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
state = simple_strtoul(argv[3], &endp, 10);
if (*argv[3] == 0 || *endp != 0)
return CMD_RET_USAGE;
ret = cros_ec_set_ldo(dev, index, state);
ret = cros_ec_set_ldo(udev, index, state);
} else {
ret = cros_ec_get_ldo(dev, index, &state);
ret = cros_ec_get_ldo(udev, index, &state);
if (!ret) {
printf("LDO%d: %s\n", index,
state == EC_LDO_STATE_ON ?
@ -1619,8 +1434,6 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
debug("%s: Could not access LDO%d\n", __func__, index);
return ret;
}
} else if (0 == strcmp("i2c", cmd)) {
ret = cros_ec_i2c_passthrough(dev, flag, argc - 2, argv + 2);
} else {
return CMD_RET_USAGE;
}
@ -1633,6 +1446,12 @@ static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return ret;
}
int cros_ec_post_bind(struct udevice *dev)
{
/* Scan for available EC devices (e.g. I2C tunnel) */
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
U_BOOT_CMD(
crosec, 6, 1, do_cros_ec,
"CROS-EC utility command",
@ -1651,9 +1470,7 @@ U_BOOT_CMD(
"crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n"
"crosec ldo <idx> [<state>] Switch/Read LDO state\n"
"crosec test run tests on cros_ec\n"
"crosec version Read CROS-EC version\n"
"crosec i2c md chip address[.0, .1, .2] [# of objects] - read from I2C passthru\n"
"crosec i2c mw chip address[.0, .1, .2] value [count] - write to I2C passthru (fill)"
"crosec version Read CROS-EC version"
);
#endif
@ -1661,4 +1478,5 @@ UCLASS_DRIVER(cros_ec) = {
.id = UCLASS_CROS_EC,
.name = "cros_ec",
.per_device_auto_alloc_size = sizeof(struct cros_ec_dev),
.post_bind = cros_ec_post_bind,
};

View File

@ -202,6 +202,6 @@ int exynos_mmc_init(const void *blob)
process_nodes(blob, node_list, count);
return 1;
return 0;
}
#endif

View File

@ -445,11 +445,11 @@ static int tegra_pcie_parse_dt_ranges(const void *fdt, int node,
}
debug("PCI regions:\n");
debug(" I/O: %#x-%#x\n", pcie->io.start, pcie->io.end);
debug(" non-prefetchable memory: %#x-%#x\n", pcie->mem.start,
pcie->mem.end);
debug(" prefetchable memory: %#x-%#x\n", pcie->prefetch.start,
pcie->prefetch.end);
debug(" I/O: %pa-%pa\n", &pcie->io.start, &pcie->io.end);
debug(" non-prefetchable memory: %pa-%pa\n", &pcie->mem.start,
&pcie->mem.end);
debug(" prefetchable memory: %pa-%pa\n", &pcie->prefetch.start,
&pcie->prefetch.end);
return 0;
}

View File

@ -41,3 +41,21 @@ config DM_PMIC_SANDBOX
- set by i2c emul driver's probe() (defaults in header)
Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt
config PMIC_S5M8767
bool "Enable Driver Model for the Samsung S5M8767 PMIC"
depends on DM_PMIC
---help---
The S5M8767 PMIC provides a large array of LDOs and BUCKs for use
as a SoC power controller. It also provides 32KHz clock outputs. This
driver provides basic register access and sets up the attached
regulators if regulator support is enabled.
config PMIC_TPS65090
bool "Enable driver for Texas Instruments TPS65090 PMIC"
depends on DM_PMIC
---help---
The TPS65090 is a PMIC containing several LDOs, DC to DC convertors,
FETs and a battery charger. This driver provides register access
only, and you can enable the regulator/charger drivers separately if
required.

View File

@ -8,6 +8,9 @@
obj-$(CONFIG_DM_PMIC) += pmic-uclass.o
obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o
obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o
obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
@ -15,8 +18,6 @@ obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o
obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o
obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o
obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o
obj-$(CONFIG_POWER_TPS65090_I2C) += pmic_tps65090.o
obj-$(CONFIG_POWER_TPS65090_EC) += pmic_tps65090_ec.o
obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o
obj-$(CONFIG_POWER_TPS65218) += pmic_tps62362.o
obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o

View File

@ -17,8 +17,8 @@
DECLARE_GLOBAL_DATA_PTR;
static const struct pmic_child_info pmic_children_info[] = {
{ .prefix = "ldo", .driver = MAX77686_LDO_DRIVER },
{ .prefix = "buck", .driver = MAX77686_BUCK_DRIVER },
{ .prefix = "LDO", .driver = MAX77686_LDO_DRIVER },
{ .prefix = "BUCK", .driver = MAX77686_BUCK_DRIVER },
{ },
};
@ -84,7 +84,7 @@ static const struct udevice_id max77686_ids[] = {
};
U_BOOT_DRIVER(pmic_max77686) = {
.name = "max77686 pmic",
.name = "max77686_pmic",
.id = UCLASS_PMIC,
.of_match = max77686_ids,
.bind = max77686_bind,

View File

@ -142,7 +142,7 @@ int pmic_reg_write(struct udevice *dev, uint reg, uint value)
u8 byte = value;
debug("%s: reg=%x, value=%x\n", __func__, reg, value);
return pmic_read(dev, reg, &byte, 1);
return pmic_write(dev, reg, &byte, 1);
}
int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set)

View File

@ -1,310 +0,0 @@
/*
* Copyright (c) 2012 The Chromium OS Authors.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <errno.h>
#include <fdtdec.h>
#include <i2c.h>
#include <power/pmic.h>
#include <power/tps65090_pmic.h>
DECLARE_GLOBAL_DATA_PTR;
#define TPS65090_NAME "TPS65090_PMIC"
/* TPS65090 register addresses */
enum {
REG_IRQ1 = 0,
REG_CG_CTRL0 = 4,
REG_CG_STATUS1 = 0xa,
REG_FET1_CTRL = 0x0f,
REG_FET2_CTRL,
REG_FET3_CTRL,
REG_FET4_CTRL,
REG_FET5_CTRL,
REG_FET6_CTRL,
REG_FET7_CTRL,
TPS65090_NUM_REGS,
};
enum {
IRQ1_VBATG = 1 << 3,
CG_CTRL0_ENC_MASK = 0x01,
MAX_FET_NUM = 7,
MAX_CTRL_READ_TRIES = 5,
/* TPS65090 FET_CTRL register values */
FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */
FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */
FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */
FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */
FET_CTRL_ENFET = 1 << 0, /* Enable FET */
};
/**
* Checks for a valid FET number
*
* @param fet_id FET number to check
* @return 0 if ok, -EINVAL if FET value is out of range
*/
static int tps65090_check_fet(unsigned int fet_id)
{
if (fet_id == 0 || fet_id > MAX_FET_NUM) {
debug("parameter fet_id is out of range, %u not in 1 ~ %u\n",
fet_id, MAX_FET_NUM);
return -EINVAL;
}
return 0;
}
/**
* Set the power state for a FET
*
* @param pmic pmic structure for the tps65090
* @param fet_id Fet number to set (1..MAX_FET_NUM)
* @param set 1 to power on FET, 0 to power off
* @return -EIO if we got a comms error, -EAGAIN if the FET failed to
* change state. If all is ok, returns 0.
*/
static int tps65090_fet_set(struct pmic *pmic, int fet_id, bool set)
{
int retry;
u32 reg, value;
value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
if (set)
value |= FET_CTRL_ENFET;
if (pmic_reg_write(pmic, REG_FET1_CTRL + fet_id - 1, value))
return -EIO;
/* Try reading until we get a result */
for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
if (pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, &reg))
return -EIO;
/* Check that the fet went into the expected state */
if (!!(reg & FET_CTRL_PGFET) == set)
return 0;
/* If we got a timeout, there is no point in waiting longer */
if (reg & FET_CTRL_TOFET)
break;
mdelay(1);
}
debug("FET %d: Power good should have set to %d but reg=%#02x\n",
fet_id, set, reg);
return -EAGAIN;
}
int tps65090_fet_enable(unsigned int fet_id)
{
struct pmic *pmic;
ulong start;
int loops;
int ret;
ret = tps65090_check_fet(fet_id);
if (ret)
return ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -EACCES;
start = get_timer(0);
for (loops = 0;; loops++) {
ret = tps65090_fet_set(pmic, fet_id, true);
if (!ret)
break;
if (get_timer(start) > 100)
break;
/* Turn it off and try again until we time out */
tps65090_fet_set(pmic, fet_id, false);
}
if (ret)
debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
else if (loops)
debug("%s: FET%d powered on after %lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
/*
* Unfortunately, there are some conditions where the power
* good bit will be 0, but the fet still comes up. One such
* case occurs with the lcd backlight. We'll just return 0 here
* and assume that the fet will eventually come up.
*/
if (ret == -EAGAIN)
ret = 0;
return ret;
}
int tps65090_fet_disable(unsigned int fet_id)
{
struct pmic *pmic;
int ret;
ret = tps65090_check_fet(fet_id);
if (ret)
return ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -EACCES;
ret = tps65090_fet_set(pmic, fet_id, false);
return ret;
}
int tps65090_fet_is_enabled(unsigned int fet_id)
{
struct pmic *pmic;
u32 reg;
int ret;
ret = tps65090_check_fet(fet_id);
if (ret)
return ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -ENODEV;
ret = pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, &reg);
if (ret) {
debug("fail to read FET%u_CTRL register over I2C", fet_id);
return -EIO;
}
return reg & FET_CTRL_ENFET;
}
int tps65090_get_charging(void)
{
struct pmic *pmic;
u32 val;
int ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -EACCES;
ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val);
if (ret)
return ret;
return !!(val & CG_CTRL0_ENC_MASK);
}
static int tps65090_charger_state(struct pmic *pmic, int state,
int current)
{
u32 val;
int ret;
ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val);
if (!ret) {
if (state == PMIC_CHARGER_ENABLE)
val |= CG_CTRL0_ENC_MASK;
else
val &= ~CG_CTRL0_ENC_MASK;
ret = pmic_reg_write(pmic, REG_CG_CTRL0, val);
}
if (ret) {
debug("%s: Failed to read/write register\n", __func__);
return ret;
}
return 0;
}
int tps65090_get_status(void)
{
struct pmic *pmic;
u32 val;
int ret;
pmic = pmic_get(TPS65090_NAME);
if (!pmic)
return -EACCES;
ret = pmic_reg_read(pmic, REG_CG_STATUS1, &val);
if (ret)
return ret;
return val;
}
static int tps65090_charger_bat_present(struct pmic *pmic)
{
u32 val;
int ret;
ret = pmic_reg_read(pmic, REG_IRQ1, &val);
if (ret)
return ret;
return !!(val & IRQ1_VBATG);
}
static struct power_chrg power_chrg_pmic_ops = {
.chrg_bat_present = tps65090_charger_bat_present,
.chrg_state = tps65090_charger_state,
};
int tps65090_init(void)
{
struct pmic *p;
int bus;
int addr;
const void *blob = gd->fdt_blob;
int node, parent;
node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090);
if (node < 0) {
debug("PMIC: No node for PMIC Chip in device tree\n");
debug("node = %d\n", node);
return -ENODEV;
}
parent = fdt_parent_offset(blob, node);
if (parent < 0) {
debug("%s: Cannot find node parent\n", __func__);
return -EINVAL;
}
bus = i2c_get_bus_num_fdt(parent);
if (bus < 0) {
debug("%s: Cannot find I2C bus\n", __func__);
return -ENOENT;
}
addr = fdtdec_get_int(blob, node, "reg", TPS65090_I2C_ADDR);
p = pmic_alloc();
if (!p) {
printf("%s: POWER allocation error!\n", __func__);
return -ENOMEM;
}
p->name = TPS65090_NAME;
p->bus = bus;
p->interface = PMIC_I2C;
p->number_of_regs = TPS65090_NUM_REGS;
p->hw.i2c.addr = addr;
p->hw.i2c.tx_num = 1;
p->chrg = &power_chrg_pmic_ops;
puts("TPS65090 PMIC init\n");
return 0;
}

View File

@ -1,218 +0,0 @@
/*
* Copyright (c) 2013 The Chromium OS Authors.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <cros_ec.h>
#include <errno.h>
#include <power/tps65090_pmic.h>
DECLARE_GLOBAL_DATA_PTR;
#define TPS65090_ADDR 0x48
static struct tps65090 {
struct cros_ec_dev *dev; /* The CROS_EC device */
} config;
/* TPS65090 register addresses */
enum {
REG_IRQ1 = 0,
REG_CG_CTRL0 = 4,
REG_CG_STATUS1 = 0xa,
REG_FET1_CTRL = 0x0f,
REG_FET2_CTRL,
REG_FET3_CTRL,
REG_FET4_CTRL,
REG_FET5_CTRL,
REG_FET6_CTRL,
REG_FET7_CTRL,
TPS65090_NUM_REGS,
};
enum {
IRQ1_VBATG = 1 << 3,
CG_CTRL0_ENC_MASK = 0x01,
MAX_FET_NUM = 7,
MAX_CTRL_READ_TRIES = 5,
/* TPS65090 FET_CTRL register values */
FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */
FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */
FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */
FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */
FET_CTRL_ENFET = 1 << 0, /* Enable FET */
};
/**
* tps65090_read - read a byte from tps6090
*
* @param reg The register address to read from.
* @param val We'll return value value read here.
* @return 0 if ok; error if EC returns failure.
*/
static int tps65090_read(u32 reg, u8 *val)
{
return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1,
val, 1, true);
}
/**
* tps65090_write - write a byte to tps6090
*
* @param reg The register address to write to.
* @param val The value to write.
* @return 0 if ok; error if EC returns failure.
*/
static int tps65090_write(u32 reg, u8 val)
{
return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1,
&val, 1, false);
}
/**
* Checks for a valid FET number
*
* @param fet_id FET number to check
* @return 0 if ok, -EINVAL if FET value is out of range
*/
static int tps65090_check_fet(unsigned int fet_id)
{
if (fet_id == 0 || fet_id > MAX_FET_NUM) {
debug("parameter fet_id is out of range, %u not in 1 ~ %u\n",
fet_id, MAX_FET_NUM);
return -EINVAL;
}
return 0;
}
/**
* Set the power state for a FET
*
* @param fet_id Fet number to set (1..MAX_FET_NUM)
* @param set 1 to power on FET, 0 to power off
* @return -EIO if we got a comms error, -EAGAIN if the FET failed to
* change state. If all is ok, returns 0.
*/
static int tps65090_fet_set(int fet_id, bool set)
{
int retry;
u8 reg, value;
value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
if (set)
value |= FET_CTRL_ENFET;
if (tps65090_write(REG_FET1_CTRL + fet_id - 1, value))
return -EIO;
/* Try reading until we get a result */
for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
if (tps65090_read(REG_FET1_CTRL + fet_id - 1, &reg))
return -EIO;
/* Check that the fet went into the expected state */
if (!!(reg & FET_CTRL_PGFET) == set)
return 0;
/* If we got a timeout, there is no point in waiting longer */
if (reg & FET_CTRL_TOFET)
break;
mdelay(1);
}
debug("FET %d: Power good should have set to %d but reg=%#02x\n",
fet_id, set, reg);
return -EAGAIN;
}
int tps65090_fet_enable(unsigned int fet_id)
{
ulong start;
int loops;
int ret;
ret = tps65090_check_fet(fet_id);
if (ret)
return ret;
start = get_timer(0);
for (loops = 0;; loops++) {
ret = tps65090_fet_set(fet_id, true);
if (!ret)
break;
if (get_timer(start) > 100)
break;
/* Turn it off and try again until we time out */
tps65090_fet_set(fet_id, false);
}
if (ret) {
debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
} else if (loops) {
debug("%s: FET%d powered on after %lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
}
/*
* Unfortunately, there are some conditions where the power
* good bit will be 0, but the fet still comes up. One such
* case occurs with the lcd backlight. We'll just return 0 here
* and assume that the fet will eventually come up.
*/
if (ret == -EAGAIN)
ret = 0;
return ret;
}
int tps65090_fet_disable(unsigned int fet_id)
{
int ret;
ret = tps65090_check_fet(fet_id);
if (ret)
return ret;
ret = tps65090_fet_set(fet_id, false);
return ret;
}
int tps65090_fet_is_enabled(unsigned int fet_id)
{
u8 reg = 0;
int ret;
ret = tps65090_check_fet(fet_id);
if (ret)
return ret;
ret = tps65090_read(REG_FET1_CTRL + fet_id - 1, &reg);
if (ret) {
debug("fail to read FET%u_CTRL register over I2C", fet_id);
return -EIO;
}
return reg & FET_CTRL_ENFET;
}
int tps65090_init(void)
{
puts("TPS65090 PMIC EC init\n");
config.dev = board_get_cros_ec_dev();
if (!config.dev) {
debug("%s: no cros_ec device: cannot init tps65090\n",
__func__);
return -ENODEV;
}
return 0;
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2015 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <fdtdec.h>
#include <errno.h>
#include <dm.h>
#include <i2c.h>
#include <power/pmic.h>
#include <power/regulator.h>
#include <power/s5m8767.h>
DECLARE_GLOBAL_DATA_PTR;
static const struct pmic_child_info pmic_children_info[] = {
{ .prefix = "LDO", .driver = S5M8767_LDO_DRIVER },
{ .prefix = "BUCK", .driver = S5M8767_BUCK_DRIVER },
{ },
};
static int s5m8767_reg_count(struct udevice *dev)
{
return S5M8767_NUM_OF_REGS;
}
static int s5m8767_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
{
if (dm_i2c_write(dev, reg, buff, len)) {
error("write error to device: %p register: %#x!", dev, reg);
return -EIO;
}
return 0;
}
static int s5m8767_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
{
if (dm_i2c_read(dev, reg, buff, len)) {
error("read error from device: %p register: %#x!", dev, reg);
return -EIO;
}
return 0;
}
int s5m8767_enable_32khz_cp(struct udevice *dev)
{
return pmic_clrsetbits(dev, S5M8767_EN32KHZ_CP, 0, 1 << 1);
}
static int s5m8767_bind(struct udevice *dev)
{
int node;
const void *blob = gd->fdt_blob;
int children;
node = fdt_subnode_offset(blob, dev->of_offset, "regulators");
if (node <= 0) {
debug("%s: %s regulators subnode not found!", __func__,
dev->name);
return -ENXIO;
}
debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
children = pmic_bind_children(dev, node, pmic_children_info);
if (!children)
debug("%s: %s - no child found\n", __func__, dev->name);
/* Always return success for this device */
return 0;
}
static struct dm_pmic_ops s5m8767_ops = {
.reg_count = s5m8767_reg_count,
.read = s5m8767_read,
.write = s5m8767_write,
};
static const struct udevice_id s5m8767_ids[] = {
{ .compatible = "samsung,s5m8767-pmic" },
{ }
};
U_BOOT_DRIVER(pmic_s5m8767) = {
.name = "s5m8767_pmic",
.id = UCLASS_PMIC,
.of_match = s5m8767_ids,
.bind = s5m8767_bind,
.ops = &s5m8767_ops,
};

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <i2c.h>
#include <power/pmic.h>
#include <power/tps65090.h>
DECLARE_GLOBAL_DATA_PTR;
static const struct pmic_child_info pmic_children_info[] = {
{ .prefix = "fet", .driver = TPS65090_FET_DRIVER },
{ },
};
static int tps65090_reg_count(struct udevice *dev)
{
return TPS65090_NUM_REGS;
}
static int tps65090_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
{
if (dm_i2c_write(dev, reg, buff, len)) {
error("write error to device: %p register: %#x!", dev, reg);
return -EIO;
}
return 0;
}
static int tps65090_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
{
int ret;
ret = dm_i2c_read(dev, reg, buff, len);
if (ret) {
error("read error %d from device: %p register: %#x!", ret, dev,
reg);
return -EIO;
}
return 0;
}
static int tps65090_bind(struct udevice *dev)
{
int regulators_node;
const void *blob = gd->fdt_blob;
int children;
regulators_node = fdt_subnode_offset(blob, dev->of_offset,
"regulators");
if (regulators_node <= 0) {
debug("%s: %s regulators subnode not found!", __func__,
dev->name);
return -ENXIO;
}
debug("%s: '%s' - found regulators subnode\n", __func__, dev->name);
children = pmic_bind_children(dev, regulators_node, pmic_children_info);
if (!children)
debug("%s: %s - no child found\n", __func__, dev->name);
/* Always return success for this device */
return 0;
}
static struct dm_pmic_ops tps65090_ops = {
.reg_count = tps65090_reg_count,
.read = tps65090_read,
.write = tps65090_write,
};
static const struct udevice_id tps65090_ids[] = {
{ .compatible = "ti,tps65090" },
{ }
};
U_BOOT_DRIVER(pmic_tps65090) = {
.name = "tps65090 pmic",
.id = UCLASS_PMIC,
.of_match = tps65090_ids,
.bind = tps65090_bind,
.ops = &tps65090_ops,
};

View File

@ -32,6 +32,15 @@ config DM_REGULATOR_FIXED
features for fixed value regulators. The driver implements get/set api
for enable and get only for voltage value.
config REGULATOR_S5M8767
bool "Enable support for S5M8767 regulator"
depends on DM_REGULATOR && PMIC_S5M8767
---help---
This enables the regulator features of the S5M8767, allowing voltages
to be set, etc. The driver is not fully complete but supports most
common requirements, including all LDOs and BUCKs. This allows many
supplies to be set automatically using the device tree values.
config DM_REGULATOR_SANDBOX
bool "Enable Driver Model for Sandbox PMIC regulator"
depends on DM_REGULATOR && DM_PMIC_SANDBOX
@ -61,3 +70,13 @@ config DM_REGULATOR_SANDBOX
A detailed information can be found in header: '<power/sandbox_pmic.h>'
Binding info: 'doc/device-tree-bindings/pmic/max77686.txt'
config REGULATOR_TPS65090
bool "Enable driver for TPS65090 PMIC regulators"
depends on PMIC_TPS65090
---help---
The TPS65090 provides several FETs (Field-effect Transistors,
effectively switches) which are supported by this driver as
regulators, one for each FET. The standard regulator interface is
supported, but it is only possible to turn the regulators on or off.
There is no voltage/current control.

View File

@ -8,4 +8,6 @@
obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o
obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o

View File

@ -61,10 +61,14 @@ static struct dm_regulator_mode max77686_buck_mode_onoff[] = {
MODE(OPMODE_ON, MAX77686_BUCK_MODE_ON, "ON"),
};
static const char max77686_buck_addr[] = {
static const char max77686_buck_ctrl[] = {
0xff, 0x10, 0x12, 0x1c, 0x26, 0x30, 0x32, 0x34, 0x36, 0x38
};
static const char max77686_buck_out[] = {
0xff, 0x11, 0x14, 0x1e, 0x28, 0x31, 0x33, 0x35, 0x37, 0x39
};
static int max77686_buck_volt2hex(int buck, int uV)
{
unsigned int hex = 0;
@ -77,13 +81,15 @@ static int max77686_buck_volt2hex(int buck, int uV)
/* hex = (uV - 600000) / 12500; */
hex = (uV - MAX77686_BUCK_UV_LMIN) / MAX77686_BUCK_UV_LSTEP;
hex_max = MAX77686_BUCK234_VOLT_MAX_HEX;
/**
* Those use voltage scaller - temporary not implemented
* so return just 0
*/
return -ENOSYS;
break;
default:
/* hex = (uV - 750000) / 50000; */
/*
* hex = (uV - 750000) / 50000. We assume that dynamic voltage
* scaling via GPIOs is not enabled and don't support that.
* If this is enabled then the driver will need to take that
* into account anrd check different registers depending on
* the current setting See the datasheet for details.
*/
hex = (uV - MAX77686_BUCK_UV_HMIN) / MAX77686_BUCK_UV_HSTEP;
hex_max = MAX77686_BUCK_VOLT_MAX_HEX;
break;
@ -368,18 +374,18 @@ static int max77686_buck_val(struct udevice *dev, int op, int *uV)
*uV = 0;
/* &buck_out = ctrl + 1 */
adr = max77686_buck_addr[buck] + 1;
adr = max77686_buck_out[buck];
/* mask */
switch (buck) {
case 2:
case 3:
case 4:
/* Those use voltage scallers - will support in the future */
mask = MAX77686_BUCK234_VOLT_MASK;
return -ENOSYS;
break;
default:
mask = MAX77686_BUCK_VOLT_MASK;
break;
}
ret = pmic_read(dev->parent, adr, &val, 1);
@ -549,7 +555,7 @@ static int max77686_buck_mode(struct udevice *dev, int op, int *opmode)
return -EINVAL;
}
adr = max77686_buck_addr[buck];
adr = max77686_buck_ctrl[buck];
/* mask */
switch (buck) {

View File

@ -319,8 +319,10 @@ int regulators_enable_boot_on(bool verbose)
dev && !ret;
uclass_next_device(&dev)) {
ret = regulator_autoset(dev);
if (ret == -EMEDIUMTYPE)
if (ret == -EMEDIUMTYPE) {
ret = 0;
continue;
}
if (verbose)
regulator_show(dev, ret);
}

View File

@ -0,0 +1,269 @@
/*
* Copyright (C) 2015 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <fdtdec.h>
#include <errno.h>
#include <dm.h>
#include <i2c.h>
#include <power/pmic.h>
#include <power/regulator.h>
#include <power/s5m8767.h>
DECLARE_GLOBAL_DATA_PTR;
static const struct sec_voltage_desc buck_v1 = {
.max = 2225000,
.min = 650000,
.step = 6250,
};
static const struct sec_voltage_desc buck_v2 = {
.max = 1600000,
.min = 600000,
.step = 6250,
};
static const struct sec_voltage_desc buck_v3 = {
.max = 3000000,
.min = 750000,
.step = 12500,
};
static const struct sec_voltage_desc ldo_v1 = {
.max = 3950000,
.min = 800000,
.step = 50000,
};
static const struct sec_voltage_desc ldo_v2 = {
.max = 2375000,
.min = 800000,
.step = 25000,
};
static const struct s5m8767_para buck_param[] = {
/*
* | voltage ----| | enable -| voltage
* regnum addr bpos mask addr on desc
*/
{S5M8767_BUCK1, 0x33, 0x0, 0xff, 0x32, 0x3, &buck_v1},
{S5M8767_BUCK2, 0x35, 0x0, 0xff, 0x34, 0x1, &buck_v2},
{S5M8767_BUCK3, 0x3e, 0x0, 0xff, 0x3d, 0x1, &buck_v2},
{S5M8767_BUCK4, 0x47, 0x0, 0xff, 0x46, 0x1, &buck_v2},
{S5M8767_BUCK5, 0x50, 0x0, 0xff, 0x4f, 0x3, &buck_v1},
{S5M8767_BUCK6, 0x55, 0x0, 0xff, 0x54, 0x3, &buck_v1},
{S5M8767_BUCK7, 0x57, 0x0, 0xff, 0x56, 0x3, &buck_v3},
{S5M8767_BUCK8, 0x59, 0x0, 0xff, 0x58, 0x3, &buck_v3},
{S5M8767_BUCK9, 0x5b, 0x0, 0xff, 0x5a, 0x3, &buck_v3},
};
static const struct s5m8767_para ldo_param[] = {
{S5M8767_LDO1, 0x5c, 0x0, 0x3f, 0x5c, 0x3, &ldo_v2},
{S5M8767_LDO2, 0x5d, 0x0, 0x3f, 0x5d, 0x1, &ldo_v2},
{S5M8767_LDO3, 0x61, 0x0, 0x3f, 0x61, 0x3, &ldo_v1},
{S5M8767_LDO4, 0x62, 0x0, 0x3f, 0x62, 0x3, &ldo_v1},
{S5M8767_LDO5, 0x63, 0x0, 0x3f, 0x63, 0x3, &ldo_v1},
{S5M8767_LDO6, 0x64, 0x0, 0x3f, 0x64, 0x1, &ldo_v2},
{S5M8767_LDO7, 0x65, 0x0, 0x3f, 0x65, 0x1, &ldo_v2},
{S5M8767_LDO8, 0x66, 0x0, 0x3f, 0x66, 0x1, &ldo_v2},
{S5M8767_LDO9, 0x67, 0x0, 0x3f, 0x67, 0x3, &ldo_v1},
{S5M8767_LDO10, 0x68, 0x0, 0x3f, 0x68, 0x1, &ldo_v1},
{S5M8767_LDO11, 0x69, 0x0, 0x3f, 0x69, 0x1, &ldo_v1},
{S5M8767_LDO12, 0x6a, 0x0, 0x3f, 0x6a, 0x1, &ldo_v1},
{S5M8767_LDO13, 0x6b, 0x0, 0x3f, 0x6b, 0x3, &ldo_v1},
{S5M8767_LDO14, 0x6c, 0x0, 0x3f, 0x6c, 0x1, &ldo_v1},
{S5M8767_LDO15, 0x6d, 0x0, 0x3f, 0x6d, 0x1, &ldo_v2},
{S5M8767_LDO16, 0x6e, 0x0, 0x3f, 0x6e, 0x1, &ldo_v1},
{S5M8767_LDO17, 0x6f, 0x0, 0x3f, 0x6f, 0x3, &ldo_v1},
{S5M8767_LDO18, 0x70, 0x0, 0x3f, 0x70, 0x3, &ldo_v1},
{S5M8767_LDO19, 0x71, 0x0, 0x3f, 0x71, 0x3, &ldo_v1},
{S5M8767_LDO20, 0x72, 0x0, 0x3f, 0x72, 0x3, &ldo_v1},
{S5M8767_LDO21, 0x73, 0x0, 0x3f, 0x73, 0x3, &ldo_v1},
{S5M8767_LDO22, 0x74, 0x0, 0x3f, 0x74, 0x3, &ldo_v1},
{S5M8767_LDO23, 0x75, 0x0, 0x3f, 0x75, 0x3, &ldo_v1},
{S5M8767_LDO24, 0x76, 0x0, 0x3f, 0x76, 0x3, &ldo_v1},
{S5M8767_LDO25, 0x77, 0x0, 0x3f, 0x77, 0x3, &ldo_v1},
{S5M8767_LDO26, 0x78, 0x0, 0x3f, 0x78, 0x3, &ldo_v1},
{S5M8767_LDO27, 0x79, 0x0, 0x3f, 0x79, 0x3, &ldo_v1},
{S5M8767_LDO28, 0x7a, 0x0, 0x3f, 0x7a, 0x3, &ldo_v1},
};
enum {
ENABLE_SHIFT = 6,
ENABLE_MASK = 3,
};
static int reg_get_value(struct udevice *dev, const struct s5m8767_para *param)
{
const struct sec_voltage_desc *desc;
int ret, uv, val;
ret = pmic_reg_read(dev->parent, param->vol_addr);
if (ret < 0)
return ret;
desc = param->vol;
val = (ret >> param->vol_bitpos) & param->vol_bitmask;
uv = desc->min + val * desc->step;
return uv;
}
static int reg_set_value(struct udevice *dev, const struct s5m8767_para *param,
int uv)
{
const struct sec_voltage_desc *desc;
int ret, val;
desc = param->vol;
if (uv < desc->min || uv > desc->max)
return -EINVAL;
val = (uv - desc->min) / desc->step;
val = (val & param->vol_bitmask) << param->vol_bitpos;
ret = pmic_clrsetbits(dev->parent, param->vol_addr,
param->vol_bitmask << param->vol_bitpos,
val);
return ret;
}
static int s5m8767_ldo_probe(struct udevice *dev)
{
struct dm_regulator_uclass_platdata *uc_pdata;
uc_pdata = dev_get_uclass_platdata(dev);
uc_pdata->type = REGULATOR_TYPE_LDO;
uc_pdata->mode_count = 0;
return 0;
}
static int ldo_get_value(struct udevice *dev)
{
int ldo = dev->driver_data;
return reg_get_value(dev, &ldo_param[ldo]);
}
static int ldo_set_value(struct udevice *dev, int uv)
{
int ldo = dev->driver_data;
return reg_set_value(dev, &ldo_param[ldo], uv);
}
static int reg_get_enable(struct udevice *dev, const struct s5m8767_para *param)
{
bool enable;
int ret;
ret = pmic_reg_read(dev->parent, param->reg_enaddr);
if (ret < 0)
return ret;
enable = (ret >> ENABLE_SHIFT) & ENABLE_MASK;
return enable;
}
static int reg_set_enable(struct udevice *dev, const struct s5m8767_para *param,
bool enable)
{
int ret;
ret = pmic_reg_read(dev->parent, param->reg_enaddr);
if (ret < 0)
return ret;
ret = pmic_clrsetbits(dev->parent, param->reg_enaddr,
ENABLE_MASK << ENABLE_SHIFT,
enable ? param->reg_enbiton << ENABLE_SHIFT : 0);
return ret;
}
static bool ldo_get_enable(struct udevice *dev)
{
int ldo = dev->driver_data;
return reg_get_enable(dev, &ldo_param[ldo]);
}
static int ldo_set_enable(struct udevice *dev, bool enable)
{
int ldo = dev->driver_data;
return reg_set_enable(dev, &ldo_param[ldo], enable);
}
static int s5m8767_buck_probe(struct udevice *dev)
{
struct dm_regulator_uclass_platdata *uc_pdata;
uc_pdata = dev_get_uclass_platdata(dev);
uc_pdata->type = REGULATOR_TYPE_BUCK;
uc_pdata->mode_count = 0;
return 0;
}
static int buck_get_value(struct udevice *dev)
{
int buck = dev->driver_data;
return reg_get_value(dev, &buck_param[buck]);
}
static int buck_set_value(struct udevice *dev, int uv)
{
int buck = dev->driver_data;
return reg_set_value(dev, &buck_param[buck], uv);
}
static bool buck_get_enable(struct udevice *dev)
{
int buck = dev->driver_data;
return reg_get_enable(dev, &buck_param[buck]);
}
static int buck_set_enable(struct udevice *dev, bool enable)
{
int buck = dev->driver_data;
return reg_set_enable(dev, &buck_param[buck], enable);
}
static const struct dm_regulator_ops s5m8767_ldo_ops = {
.get_value = ldo_get_value,
.set_value = ldo_set_value,
.get_enable = ldo_get_enable,
.set_enable = ldo_set_enable,
};
U_BOOT_DRIVER(s5m8767_ldo) = {
.name = S5M8767_LDO_DRIVER,
.id = UCLASS_REGULATOR,
.ops = &s5m8767_ldo_ops,
.probe = s5m8767_ldo_probe,
};
static const struct dm_regulator_ops s5m8767_buck_ops = {
.get_value = buck_get_value,
.set_value = buck_set_value,
.get_enable = buck_get_enable,
.set_enable = buck_set_enable,
};
U_BOOT_DRIVER(s5m8767_buck) = {
.name = S5M8767_BUCK_DRIVER,
.id = UCLASS_REGULATOR,
.ops = &s5m8767_buck_ops,
.probe = s5m8767_buck_probe,
};

View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2015 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <power/pmic.h>
#include <power/regulator.h>
#include <power/tps65090.h>
static int tps65090_fet_probe(struct udevice *dev)
{
struct dm_regulator_uclass_platdata *uc_pdata;
uc_pdata = dev_get_uclass_platdata(dev);
uc_pdata->type = REGULATOR_TYPE_OTHER;
uc_pdata->mode_count = 0;
return 0;
}
static bool tps65090_fet_get_enable(struct udevice *dev)
{
struct udevice *pmic = dev_get_parent(dev);
int ret, fet_id;
fet_id = dev->driver_data;
debug("%s: fet_id=%d\n", __func__, fet_id);
ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
if (ret < 0)
return ret;
return ret & FET_CTRL_ENFET;
}
/**
* Set the power state for a FET
*
* @param pmic pmic structure for the tps65090
* @param fet_id FET number to set (1..MAX_FET_NUM)
* @param set 1 to power on FET, 0 to power off
* @return -EIO if we got a comms error, -EAGAIN if the FET failed to
* change state. If all is ok, returns 0.
*/
static int tps65090_fet_set(struct udevice *pmic, int fet_id, bool set)
{
int retry;
u32 value;
int ret;
value = FET_CTRL_ADENFET | FET_CTRL_WAIT;
if (set)
value |= FET_CTRL_ENFET;
if (pmic_reg_write(pmic, REG_FET_BASE + fet_id, value))
return -EIO;
/* Try reading until we get a result */
for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) {
ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id);
if (ret < 0)
return ret;
/* Check that the FET went into the expected state */
debug("%s: flags=%x\n", __func__, ret);
if (!!(ret & FET_CTRL_PGFET) == set)
return 0;
/* If we got a timeout, there is no point in waiting longer */
if (ret & FET_CTRL_TOFET)
break;
mdelay(1);
}
debug("FET %d: Power good should have set to %d but reg=%#02x\n",
fet_id, set, ret);
return -EAGAIN;
}
static int tps65090_fet_set_enable(struct udevice *dev, bool enable)
{
struct udevice *pmic = dev_get_parent(dev);
int ret, fet_id;
ulong start;
int loops;
fet_id = dev->driver_data;
debug("%s: fet_id=%d, enable=%d\n", __func__, fet_id, enable);
start = get_timer(0);
for (loops = 0;; loops++) {
ret = tps65090_fet_set(pmic, fet_id, enable);
if (!ret)
break;
if (get_timer(start) > 100)
break;
/* Turn it off and try again until we time out */
tps65090_fet_set(pmic, fet_id, false);
}
if (ret)
debug("%s: FET%d failed to power on: time=%lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
else if (loops)
debug("%s: FET%d powered on after %lums, loops=%d\n",
__func__, fet_id, get_timer(start), loops);
/*
* Unfortunately there are some conditions where the power-good bit
* will be 0, but the FET still comes up. One such case occurs with
* the LCD backlight on snow. We'll just return 0 here and assume
* that the FET will eventually come up.
*/
if (ret == -EAGAIN)
ret = 0;
return ret;
}
static const struct dm_regulator_ops tps65090_fet_ops = {
.get_enable = tps65090_fet_get_enable,
.set_enable = tps65090_fet_set_enable,
};
U_BOOT_DRIVER(tps65090_fet) = {
.name = TPS65090_FET_DRIVER,
.id = UCLASS_REGULATOR,
.ops = &tps65090_fet_ops,
.probe = tps65090_fet_probe,
};

View File

@ -53,6 +53,13 @@ config DEBUG_EFI_CONSOLE
U-Boot when running on top of EFI (Extensive Firmware Interface).
This is a type of BIOS used by PCs.
config DEBUG_UART_S5P
bool "Samsung S5P"
help
Select this to enable a debug UART using the serial_s5p driver. You
will need to provide parameters to make this work. The driver will
be available until the real driver-model serial is running.
endchoice
config DEBUG_UART_BASE

View File

@ -14,8 +14,8 @@
#include <fdtdec.h>
#include <linux/compiler.h>
#include <asm/io.h>
#include <asm/arch/uart.h>
#include <asm/arch/clk.h>
#include <asm/arch/uart.h>
#include <serial.h>
DECLARE_GLOBAL_DATA_PTR;
@ -59,11 +59,20 @@ static const int udivslot[] = {
0xffdf,
};
int s5p_serial_setbrg(struct udevice *dev, int baudrate)
static void __maybe_unused s5p_serial_init(struct s5p_uart *uart)
{
/* enable FIFOs, auto clear Rx FIFO */
writel(0x3, &uart->ufcon);
writel(0, &uart->umcon);
/* 8N1 */
writel(0x3, &uart->ulcon);
/* No interrupts, no DMA, pure polling */
writel(0x245, &uart->ucon);
}
static void __maybe_unused s5p_serial_baud(struct s5p_uart *uart, uint uclk,
int baudrate)
{
struct s5p_serial_platdata *plat = dev->platdata;
struct s5p_uart *const uart = plat->reg;
u32 uclk = get_uart_clk(plat->port_id);
u32 val;
val = uclk / baudrate;
@ -74,6 +83,16 @@ int s5p_serial_setbrg(struct udevice *dev, int baudrate)
writew(udivslot[val % 16], &uart->rest.slot);
else
writeb(val % 16, &uart->rest.value);
}
#ifndef CONFIG_SPL_BUILD
int s5p_serial_setbrg(struct udevice *dev, int baudrate)
{
struct s5p_serial_platdata *plat = dev->platdata;
struct s5p_uart *const uart = plat->reg;
u32 uclk = get_uart_clk(plat->port_id);
s5p_serial_baud(uart, uclk, baudrate);
return 0;
}
@ -83,13 +102,7 @@ static int s5p_serial_probe(struct udevice *dev)
struct s5p_serial_platdata *plat = dev->platdata;
struct s5p_uart *const uart = plat->reg;
/* enable FIFOs, auto clear Rx FIFO */
writel(0x3, &uart->ufcon);
writel(0, &uart->umcon);
/* 8N1 */
writel(0x3, &uart->ulcon);
/* No interrupts, no DMA, pure polling */
writel(0x245, &uart->ucon);
s5p_serial_init(uart);
return 0;
}
@ -188,3 +201,29 @@ U_BOOT_DRIVER(serial_s5p) = {
.ops = &s5p_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
#endif
#ifdef CONFIG_DEBUG_UART_S5P
#include <debug_uart.h>
void debug_uart_init(void)
{
struct s5p_uart *uart = (struct s5p_uart *)CONFIG_DEBUG_UART_BASE;
s5p_serial_init(uart);
s5p_serial_baud(uart, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
}
static inline void _debug_uart_putc(int ch)
{
struct s5p_uart *uart = (struct s5p_uart *)CONFIG_DEBUG_UART_BASE;
while (readl(&uart->ufstat) & TX_FIFO_FULL);
writeb(ch, &uart->utxh);
}
DEBUG_UART_FUNCS
#endif

View File

@ -190,9 +190,9 @@ static int spi_rx_tx(struct exynos_spi_priv *priv, int todo,
spi_request_bytes(regs, toread, step);
}
if (priv->skip_preamble && get_timer(start) > 100) {
printf("SPI timeout: in_bytes=%d, out_bytes=%d, ",
in_bytes, out_bytes);
return -1;
debug("SPI timeout: in_bytes=%d, out_bytes=%d, ",
in_bytes, out_bytes);
return -ETIMEDOUT;
}
}

View File

@ -664,8 +664,8 @@ static int fsl_dspi_ofdata_to_platdata(struct udevice *bus)
plat->speed_hz = fdtdec_get_int(blob,
node, "spi-max-frequency", FSL_DSPI_DEFAULT_SCK_FREQ);
debug("DSPI: regs=0x%llx, max-frequency=%d, endianess=%s, num-cs=%d\n",
(u64)plat->regs_addr, plat->speed_hz,
debug("DSPI: regs=%pa, max-frequency=%d, endianess=%s, num-cs=%d\n",
&plat->regs_addr, plat->speed_hz,
plat->flags & DSPI_FLAG_REGMAP_ENDIAN_BIG ? "be" : "le",
plat->num_chipselect);

View File

@ -1,4 +1,5 @@
/*
* Copyright (c) 2015 Google, Inc
* Copyright (c) 2011 The Chromium OS Authors.
* Copyright (C) 2009 NVIDIA, Corporation
* Copyright (C) 2007-2008 SMSC (Steve Glendinning)
@ -6,12 +7,14 @@
* SPDX-License-Identifier: GPL-2.0+
*/
#include <asm/unaligned.h>
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <usb.h>
#include <asm/unaligned.h>
#include <linux/mii.h>
#include "usb_ether.h"
#include <malloc.h>
/* SMSC LAN95xx based USB 2.0 Ethernet Devices */
@ -131,16 +134,21 @@
#define USB_BULK_SEND_TIMEOUT 5000
#define USB_BULK_RECV_TIMEOUT 5000
#define AX_RX_URB_SIZE 2048
#define RX_URB_SIZE 2048
#define PHY_CONNECT_TIMEOUT 5000
#define TURBO_MODE
#ifndef CONFIG_DM_ETH
/* local vars */
static int curr_eth_dev; /* index for name of next device detected */
#endif
/* driver private */
struct smsc95xx_private {
#ifdef CONFIG_DM_ETH
struct ueth_data ueth;
#endif
size_t rx_urb_size; /* maximum USB URB size */
u32 mac_cr; /* MAC control register value */
int have_hwaddr; /* 1 if we have a hardware MAC address */
@ -149,7 +157,7 @@ struct smsc95xx_private {
/*
* Smsc95xx infrastructure commands
*/
static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data)
static int smsc95xx_write_reg(struct usb_device *udev, u32 index, u32 data)
{
int len;
ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
@ -157,32 +165,34 @@ static int smsc95xx_write_reg(struct ueth_data *dev, u32 index, u32 data)
cpu_to_le32s(&data);
tmpbuf[0] = data;
len = usb_control_msg(dev->pusb_dev, usb_sndctrlpipe(dev->pusb_dev, 0),
USB_VENDOR_REQUEST_WRITE_REGISTER,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
00, index, tmpbuf, sizeof(data), USB_CTRL_SET_TIMEOUT);
len = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_VENDOR_REQUEST_WRITE_REGISTER,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, tmpbuf, sizeof(data),
USB_CTRL_SET_TIMEOUT);
if (len != sizeof(data)) {
debug("smsc95xx_write_reg failed: index=%d, data=%d, len=%d",
index, data, len);
return -1;
return -EIO;
}
return 0;
}
static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data)
static int smsc95xx_read_reg(struct usb_device *udev, u32 index, u32 *data)
{
int len;
ALLOC_CACHE_ALIGN_BUFFER(u32, tmpbuf, 1);
len = usb_control_msg(dev->pusb_dev, usb_rcvctrlpipe(dev->pusb_dev, 0),
USB_VENDOR_REQUEST_READ_REGISTER,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
00, index, tmpbuf, sizeof(data), USB_CTRL_GET_TIMEOUT);
len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_VENDOR_REQUEST_READ_REGISTER,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, tmpbuf, sizeof(data),
USB_CTRL_GET_TIMEOUT);
*data = tmpbuf[0];
if (len != sizeof(data)) {
debug("smsc95xx_read_reg failed: index=%d, len=%d",
index, len);
return -1;
return -EIO;
}
le32_to_cpus(data);
@ -190,89 +200,89 @@ static int smsc95xx_read_reg(struct ueth_data *dev, u32 index, u32 *data)
}
/* Loop until the read is completed with timeout */
static int smsc95xx_phy_wait_not_busy(struct ueth_data *dev)
static int smsc95xx_phy_wait_not_busy(struct usb_device *udev)
{
unsigned long start_time = get_timer(0);
u32 val;
do {
smsc95xx_read_reg(dev, MII_ADDR, &val);
smsc95xx_read_reg(udev, MII_ADDR, &val);
if (!(val & MII_BUSY_))
return 0;
} while (get_timer(start_time) < 1 * 1000 * 1000);
} while (get_timer(start_time) < 1000);
return -1;
return -ETIMEDOUT;
}
static int smsc95xx_mdio_read(struct ueth_data *dev, int phy_id, int idx)
static int smsc95xx_mdio_read(struct usb_device *udev, int phy_id, int idx)
{
u32 val, addr;
/* confirm MII not busy */
if (smsc95xx_phy_wait_not_busy(dev)) {
if (smsc95xx_phy_wait_not_busy(udev)) {
debug("MII is busy in smsc95xx_mdio_read\n");
return -1;
return -ETIMEDOUT;
}
/* set the address, index & direction (read from PHY) */
addr = (phy_id << 11) | (idx << 6) | MII_READ_;
smsc95xx_write_reg(dev, MII_ADDR, addr);
smsc95xx_write_reg(udev, MII_ADDR, addr);
if (smsc95xx_phy_wait_not_busy(dev)) {
if (smsc95xx_phy_wait_not_busy(udev)) {
debug("Timed out reading MII reg %02X\n", idx);
return -1;
return -ETIMEDOUT;
}
smsc95xx_read_reg(dev, MII_DATA, &val);
smsc95xx_read_reg(udev, MII_DATA, &val);
return (u16)(val & 0xFFFF);
}
static void smsc95xx_mdio_write(struct ueth_data *dev, int phy_id, int idx,
static void smsc95xx_mdio_write(struct usb_device *udev, int phy_id, int idx,
int regval)
{
u32 val, addr;
/* confirm MII not busy */
if (smsc95xx_phy_wait_not_busy(dev)) {
if (smsc95xx_phy_wait_not_busy(udev)) {
debug("MII is busy in smsc95xx_mdio_write\n");
return;
}
val = regval;
smsc95xx_write_reg(dev, MII_DATA, val);
smsc95xx_write_reg(udev, MII_DATA, val);
/* set the address, index & direction (write to PHY) */
addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
smsc95xx_write_reg(dev, MII_ADDR, addr);
smsc95xx_write_reg(udev, MII_ADDR, addr);
if (smsc95xx_phy_wait_not_busy(dev))
if (smsc95xx_phy_wait_not_busy(udev))
debug("Timed out writing MII reg %02X\n", idx);
}
static int smsc95xx_eeprom_confirm_not_busy(struct ueth_data *dev)
static int smsc95xx_eeprom_confirm_not_busy(struct usb_device *udev)
{
unsigned long start_time = get_timer(0);
u32 val;
do {
smsc95xx_read_reg(dev, E2P_CMD, &val);
smsc95xx_read_reg(udev, E2P_CMD, &val);
if (!(val & E2P_CMD_BUSY_))
return 0;
udelay(40);
} while (get_timer(start_time) < 1 * 1000 * 1000);
debug("EEPROM is busy\n");
return -1;
return -ETIMEDOUT;
}
static int smsc95xx_wait_eeprom(struct ueth_data *dev)
static int smsc95xx_wait_eeprom(struct usb_device *udev)
{
unsigned long start_time = get_timer(0);
u32 val;
do {
smsc95xx_read_reg(dev, E2P_CMD, &val);
smsc95xx_read_reg(udev, E2P_CMD, &val);
if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_))
break;
udelay(40);
@ -280,30 +290,30 @@ static int smsc95xx_wait_eeprom(struct ueth_data *dev)
if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) {
debug("EEPROM read operation timeout\n");
return -1;
return -ETIMEDOUT;
}
return 0;
}
static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length,
static int smsc95xx_read_eeprom(struct usb_device *udev, u32 offset, u32 length,
u8 *data)
{
u32 val;
int i, ret;
ret = smsc95xx_eeprom_confirm_not_busy(dev);
ret = smsc95xx_eeprom_confirm_not_busy(udev);
if (ret)
return ret;
for (i = 0; i < length; i++) {
val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
smsc95xx_write_reg(dev, E2P_CMD, val);
smsc95xx_write_reg(udev, E2P_CMD, val);
ret = smsc95xx_wait_eeprom(dev);
ret = smsc95xx_wait_eeprom(udev);
if (ret < 0)
return ret;
smsc95xx_read_reg(dev, E2P_DATA, &val);
smsc95xx_read_reg(udev, E2P_DATA, &val);
data[i] = val & 0xFF;
offset++;
}
@ -315,89 +325,96 @@ static int smsc95xx_read_eeprom(struct ueth_data *dev, u32 offset, u32 length,
*
* Returns 0 on success, negative on error.
*/
static int mii_nway_restart(struct ueth_data *dev)
static int mii_nway_restart(struct usb_device *udev, struct ueth_data *dev)
{
int bmcr;
int r = -1;
/* if autoneg is off, it's an error */
bmcr = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMCR);
bmcr = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMCR);
if (bmcr & BMCR_ANENABLE) {
bmcr |= BMCR_ANRESTART;
smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, bmcr);
smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, bmcr);
r = 0;
}
return r;
}
static int smsc95xx_phy_initialize(struct ueth_data *dev)
static int smsc95xx_phy_initialize(struct usb_device *udev,
struct ueth_data *dev)
{
smsc95xx_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET);
smsc95xx_mdio_write(dev, dev->phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM);
smsc95xx_mdio_write(udev, dev->phy_id, MII_BMCR, BMCR_RESET);
smsc95xx_mdio_write(udev, dev->phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA |
ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
/* read to clear */
smsc95xx_mdio_read(dev, dev->phy_id, PHY_INT_SRC);
smsc95xx_mdio_read(udev, dev->phy_id, PHY_INT_SRC);
smsc95xx_mdio_write(dev, dev->phy_id, PHY_INT_MASK,
PHY_INT_MASK_DEFAULT_);
mii_nway_restart(dev);
smsc95xx_mdio_write(udev, dev->phy_id, PHY_INT_MASK,
PHY_INT_MASK_DEFAULT_);
mii_nway_restart(udev, dev);
debug("phy initialised succesfully\n");
return 0;
}
static int smsc95xx_init_mac_address(struct eth_device *eth,
struct ueth_data *dev)
static int smsc95xx_init_mac_address(unsigned char *enetaddr,
struct usb_device *udev)
{
int ret;
/* try reading mac address from EEPROM */
if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
eth->enetaddr) == 0) {
if (is_valid_ethaddr(eth->enetaddr)) {
/* eeprom values are valid so use them */
debug("MAC address read from EEPROM\n");
return 0;
}
ret = smsc95xx_read_eeprom(udev, EEPROM_MAC_OFFSET, ETH_ALEN, enetaddr);
if (ret)
return ret;
if (is_valid_ethaddr(enetaddr)) {
/* eeprom values are valid so use them */
debug("MAC address read from EEPROM\n");
return 0;
}
/*
* No eeprom, or eeprom values are invalid. Generating a random MAC
* address is not safe. Just return an error.
*/
return -1;
debug("Invalid MAC address read from EEPROM\n");
return -ENXIO;
}
static int smsc95xx_write_hwaddr(struct eth_device *eth)
static int smsc95xx_write_hwaddr_common(struct usb_device *udev,
struct smsc95xx_private *priv,
unsigned char *enetaddr)
{
struct ueth_data *dev = (struct ueth_data *)eth->priv;
struct smsc95xx_private *priv = dev->dev_priv;
u32 addr_lo = __get_unaligned_le32(&eth->enetaddr[0]);
u32 addr_hi = __get_unaligned_le16(&eth->enetaddr[4]);
u32 addr_lo = __get_unaligned_le32(&enetaddr[0]);
u32 addr_hi = __get_unaligned_le16(&enetaddr[4]);
int ret;
/* set hardware address */
debug("** %s()\n", __func__);
ret = smsc95xx_write_reg(dev, ADDRL, addr_lo);
ret = smsc95xx_write_reg(udev, ADDRL, addr_lo);
if (ret < 0)
return ret;
ret = smsc95xx_write_reg(dev, ADDRH, addr_hi);
ret = smsc95xx_write_reg(udev, ADDRH, addr_hi);
if (ret < 0)
return ret;
debug("MAC %pM\n", eth->enetaddr);
debug("MAC %pM\n", enetaddr);
priv->have_hwaddr = 1;
return 0;
}
/* Enable or disable Tx & Rx checksum offload engines */
static int smsc95xx_set_csums(struct ueth_data *dev,
int use_tx_csum, int use_rx_csum)
static int smsc95xx_set_csums(struct usb_device *udev, int use_tx_csum,
int use_rx_csum)
{
u32 read_buf;
int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
int ret = smsc95xx_read_reg(udev, COE_CR, &read_buf);
if (ret < 0)
return ret;
@ -411,7 +428,7 @@ static int smsc95xx_set_csums(struct ueth_data *dev,
else
read_buf &= ~Rx_COE_EN_;
ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
ret = smsc95xx_write_reg(udev, COE_CR, read_buf);
if (ret < 0)
return ret;
@ -419,52 +436,45 @@ static int smsc95xx_set_csums(struct ueth_data *dev,
return 0;
}
static void smsc95xx_set_multicast(struct ueth_data *dev)
static void smsc95xx_set_multicast(struct smsc95xx_private *priv)
{
struct smsc95xx_private *priv = dev->dev_priv;
/* No multicast in u-boot */
priv->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
}
/* starts the TX path */
static void smsc95xx_start_tx_path(struct ueth_data *dev)
static void smsc95xx_start_tx_path(struct usb_device *udev,
struct smsc95xx_private *priv)
{
struct smsc95xx_private *priv = dev->dev_priv;
u32 reg_val;
/* Enable Tx at MAC */
priv->mac_cr |= MAC_CR_TXEN_;
smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr);
smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr);
/* Enable Tx at SCSRs */
reg_val = TX_CFG_ON_;
smsc95xx_write_reg(dev, TX_CFG, reg_val);
smsc95xx_write_reg(udev, TX_CFG, reg_val);
}
/* Starts the Receive path */
static void smsc95xx_start_rx_path(struct ueth_data *dev)
static void smsc95xx_start_rx_path(struct usb_device *udev,
struct smsc95xx_private *priv)
{
struct smsc95xx_private *priv = dev->dev_priv;
priv->mac_cr |= MAC_CR_RXEN_;
smsc95xx_write_reg(dev, MAC_CR, priv->mac_cr);
smsc95xx_write_reg(udev, MAC_CR, priv->mac_cr);
}
/*
* Smsc95xx callbacks
*/
static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
static int smsc95xx_init_common(struct usb_device *udev, struct ueth_data *dev,
struct smsc95xx_private *priv,
unsigned char *enetaddr)
{
int ret;
u32 write_buf;
u32 read_buf;
u32 burst_cap;
int timeout;
struct ueth_data *dev = (struct ueth_data *)eth->priv;
struct smsc95xx_private *priv =
(struct smsc95xx_private *)dev->dev_priv;
#define TIMEOUT_RESOLUTION 50 /* ms */
int link_detected;
@ -472,13 +482,13 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
dev->phy_id = SMSC95XX_INTERNAL_PHY_ID; /* fixed phy id */
write_buf = HW_CFG_LRST_;
ret = smsc95xx_write_reg(dev, HW_CFG, write_buf);
ret = smsc95xx_write_reg(udev, HW_CFG, write_buf);
if (ret < 0)
return ret;
timeout = 0;
do {
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
udelay(10 * 1000);
@ -487,17 +497,17 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
if (timeout >= 100) {
debug("timeout waiting for completion of Lite Reset\n");
return -1;
return -ETIMEDOUT;
}
write_buf = PM_CTL_PHY_RST_;
ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf);
ret = smsc95xx_write_reg(udev, PM_CTRL, write_buf);
if (ret < 0)
return ret;
timeout = 0;
do {
ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
ret = smsc95xx_read_reg(udev, PM_CTRL, &read_buf);
if (ret < 0)
return ret;
udelay(10 * 1000);
@ -505,28 +515,30 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
} while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
if (timeout >= 100) {
debug("timeout waiting for PHY Reset\n");
return -1;
return -ETIMEDOUT;
}
if (!priv->have_hwaddr && smsc95xx_init_mac_address(eth, dev) == 0)
if (!priv->have_hwaddr && smsc95xx_init_mac_address(enetaddr, udev) ==
0)
priv->have_hwaddr = 1;
if (!priv->have_hwaddr) {
puts("Error: SMSC95xx: No MAC address set - set usbethaddr\n");
return -1;
return -EADDRNOTAVAIL;
}
if (smsc95xx_write_hwaddr(eth) < 0)
return -1;
ret = smsc95xx_write_hwaddr_common(udev, priv, enetaddr);
if (ret < 0)
return ret;
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from HW_CFG : 0x%08x\n", read_buf);
read_buf |= HW_CFG_BIR_;
ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
ret = smsc95xx_write_reg(udev, HW_CFG, read_buf);
if (ret < 0)
return ret;
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from HW_CFG after writing "
@ -546,27 +558,27 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
#endif
debug("rx_urb_size=%ld\n", (ulong)priv->rx_urb_size);
ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
ret = smsc95xx_write_reg(udev, BURST_CAP, burst_cap);
if (ret < 0)
return ret;
ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
ret = smsc95xx_read_reg(udev, BURST_CAP, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from BURST_CAP after writing: 0x%08x\n", read_buf);
read_buf = DEFAULT_BULK_IN_DELAY;
ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf);
ret = smsc95xx_write_reg(udev, BULK_IN_DLY, read_buf);
if (ret < 0)
return ret;
ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
ret = smsc95xx_read_reg(udev, BULK_IN_DLY, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from BULK_IN_DLY after writing: "
"0x%08x\n", read_buf);
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from HW_CFG: 0x%08x\n", read_buf);
@ -579,21 +591,21 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
#define NET_IP_ALIGN 0
read_buf |= NET_IP_ALIGN << 9;
ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
ret = smsc95xx_write_reg(udev, HW_CFG, read_buf);
if (ret < 0)
return ret;
ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
ret = smsc95xx_read_reg(udev, HW_CFG, &read_buf);
if (ret < 0)
return ret;
debug("Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
write_buf = 0xFFFFFFFF;
ret = smsc95xx_write_reg(dev, INT_STS, write_buf);
ret = smsc95xx_write_reg(udev, INT_STS, write_buf);
if (ret < 0)
return ret;
ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
ret = smsc95xx_read_reg(udev, ID_REV, &read_buf);
if (ret < 0)
return ret;
debug("ID_REV = 0x%08x\n", read_buf);
@ -601,59 +613,60 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
/* Configure GPIO pins as LED outputs */
write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
LED_GPIO_CFG_FDX_LED;
ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
ret = smsc95xx_write_reg(udev, LED_GPIO_CFG, write_buf);
if (ret < 0)
return ret;
debug("LED_GPIO_CFG set\n");
/* Init Tx */
write_buf = 0;
ret = smsc95xx_write_reg(dev, FLOW, write_buf);
ret = smsc95xx_write_reg(udev, FLOW, write_buf);
if (ret < 0)
return ret;
read_buf = AFC_CFG_DEFAULT;
ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf);
ret = smsc95xx_write_reg(udev, AFC_CFG, read_buf);
if (ret < 0)
return ret;
ret = smsc95xx_read_reg(dev, MAC_CR, &priv->mac_cr);
ret = smsc95xx_read_reg(udev, MAC_CR, &priv->mac_cr);
if (ret < 0)
return ret;
/* Init Rx. Set Vlan */
write_buf = (u32)ETH_P_8021Q;
ret = smsc95xx_write_reg(dev, VLAN1, write_buf);
ret = smsc95xx_write_reg(udev, VLAN1, write_buf);
if (ret < 0)
return ret;
/* Disable checksum offload engines */
ret = smsc95xx_set_csums(dev, 0, 0);
ret = smsc95xx_set_csums(udev, 0, 0);
if (ret < 0) {
debug("Failed to set csum offload: %d\n", ret);
return ret;
}
smsc95xx_set_multicast(dev);
smsc95xx_set_multicast(priv);
if (smsc95xx_phy_initialize(dev) < 0)
return -1;
ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
ret = smsc95xx_phy_initialize(udev, dev);
if (ret < 0)
return ret;
ret = smsc95xx_read_reg(udev, INT_EP_CTL, &read_buf);
if (ret < 0)
return ret;
/* enable PHY interrupts */
read_buf |= INT_EP_CTL_PHY_INT_;
ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
ret = smsc95xx_write_reg(udev, INT_EP_CTL, read_buf);
if (ret < 0)
return ret;
smsc95xx_start_tx_path(dev);
smsc95xx_start_rx_path(dev);
smsc95xx_start_tx_path(udev, priv);
smsc95xx_start_rx_path(udev, priv);
timeout = 0;
do {
link_detected = smsc95xx_mdio_read(dev, dev->phy_id, MII_BMSR)
link_detected = smsc95xx_mdio_read(udev, dev->phy_id, MII_BMSR)
& BMSR_LSTATUS;
if (!link_detected) {
if (timeout == 0)
@ -667,14 +680,13 @@ static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
printf("done.\n");
} else {
printf("unable to connect.\n");
return -1;
return -EIO;
}
return 0;
}
static int smsc95xx_send(struct eth_device *eth, void* packet, int length)
static int smsc95xx_send_common(struct ueth_data *dev, void *packet, int length)
{
struct ueth_data *dev = (struct ueth_data *)eth->priv;
int err;
int actual_len;
u32 tx_cmd_a;
@ -684,7 +696,7 @@ static int smsc95xx_send(struct eth_device *eth, void* packet, int length)
debug("** %s(), len %d, buf %#x\n", __func__, length, (int)msg);
if (length > PKTSIZE)
return -1;
return -ENOSPC;
tx_cmd_a = (u32)length | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
tx_cmd_b = (u32)length;
@ -705,13 +717,35 @@ static int smsc95xx_send(struct eth_device *eth, void* packet, int length)
debug("Tx: len = %u, actual = %u, err = %d\n",
length + sizeof(tx_cmd_a) + sizeof(tx_cmd_b),
actual_len, err);
return err;
}
#ifndef CONFIG_DM_ETH
/*
* Smsc95xx callbacks
*/
static int smsc95xx_init(struct eth_device *eth, bd_t *bd)
{
struct ueth_data *dev = (struct ueth_data *)eth->priv;
struct usb_device *udev = dev->pusb_dev;
struct smsc95xx_private *priv =
(struct smsc95xx_private *)dev->dev_priv;
return smsc95xx_init_common(udev, dev, priv, eth->enetaddr);
}
static int smsc95xx_send(struct eth_device *eth, void *packet, int length)
{
struct ueth_data *dev = (struct ueth_data *)eth->priv;
return smsc95xx_send_common(dev, packet, length);
}
static int smsc95xx_recv(struct eth_device *eth)
{
struct ueth_data *dev = (struct ueth_data *)eth->priv;
DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, AX_RX_URB_SIZE);
DEFINE_CACHE_ALIGN_BUFFER(unsigned char, recv_buf, RX_URB_SIZE);
unsigned char *buf_ptr;
int err;
int actual_len;
@ -720,20 +754,18 @@ static int smsc95xx_recv(struct eth_device *eth)
debug("** %s()\n", __func__);
err = usb_bulk_msg(dev->pusb_dev,
usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
(void *)recv_buf,
AX_RX_URB_SIZE,
&actual_len,
USB_BULK_RECV_TIMEOUT);
debug("Rx: len = %u, actual = %u, err = %d\n", AX_RX_URB_SIZE,
usb_rcvbulkpipe(dev->pusb_dev, dev->ep_in),
(void *)recv_buf, RX_URB_SIZE, &actual_len,
USB_BULK_RECV_TIMEOUT);
debug("Rx: len = %u, actual = %u, err = %d\n", RX_URB_SIZE,
actual_len, err);
if (err != 0) {
debug("Rx: failed to receive\n");
return -1;
return -err;
}
if (actual_len > AX_RX_URB_SIZE) {
if (actual_len > RX_URB_SIZE) {
debug("Rx: received too many bytes %d\n", actual_len);
return -1;
return -ENOSPC;
}
buf_ptr = recv_buf;
@ -744,19 +776,19 @@ static int smsc95xx_recv(struct eth_device *eth)
*/
if (actual_len < sizeof(packet_len)) {
debug("Rx: incomplete packet length\n");
return -1;
return -EIO;
}
memcpy(&packet_len, buf_ptr, sizeof(packet_len));
le32_to_cpus(&packet_len);
if (packet_len & RX_STS_ES_) {
debug("Rx: Error header=%#x", packet_len);
return -1;
return -EIO;
}
packet_len = ((packet_len & RX_STS_FL_) >> 16);
if (packet_len > actual_len - sizeof(packet_len)) {
debug("Rx: too large packet: %d\n", packet_len);
return -1;
return -EIO;
}
/* Notify net stack */
@ -783,6 +815,15 @@ static void smsc95xx_halt(struct eth_device *eth)
debug("** %s()\n", __func__);
}
static int smsc95xx_write_hwaddr(struct eth_device *eth)
{
struct ueth_data *dev = eth->priv;
struct usb_device *udev = dev->pusb_dev;
struct smsc95xx_private *priv = dev->dev_priv;
return smsc95xx_write_hwaddr_common(udev, priv, eth->enetaddr);
}
/*
* SMSC probing functions
*/
@ -898,3 +939,137 @@ int smsc95xx_eth_get_info(struct usb_device *dev, struct ueth_data *ss,
eth->priv = ss;
return 1;
}
#endif /* !CONFIG_DM_ETH */
#ifdef CONFIG_DM_ETH
static int smsc95xx_eth_start(struct udevice *dev)
{
struct usb_device *udev = dev_get_parentdata(dev);
struct smsc95xx_private *priv = dev_get_priv(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
/* Driver-model Ethernet ensures we have this */
priv->have_hwaddr = 1;
return smsc95xx_init_common(udev, &priv->ueth, priv, pdata->enetaddr);
}
void smsc95xx_eth_stop(struct udevice *dev)
{
debug("** %s()\n", __func__);
}
int smsc95xx_eth_send(struct udevice *dev, void *packet, int length)
{
struct smsc95xx_private *priv = dev_get_priv(dev);
return smsc95xx_send_common(&priv->ueth, packet, length);
}
int smsc95xx_eth_recv(struct udevice *dev, int flags, uchar **packetp)
{
struct smsc95xx_private *priv = dev_get_priv(dev);
struct ueth_data *ueth = &priv->ueth;
uint8_t *ptr;
int ret, len;
u32 packet_len;
len = usb_ether_get_rx_bytes(ueth, &ptr);
debug("%s: first try, len=%d\n", __func__, len);
if (!len) {
if (!(flags & ETH_RECV_CHECK_DEVICE))
return -EAGAIN;
ret = usb_ether_receive(ueth, RX_URB_SIZE);
if (ret == -EAGAIN)
return ret;
len = usb_ether_get_rx_bytes(ueth, &ptr);
debug("%s: second try, len=%d\n", __func__, len);
}
/*
* 1st 4 bytes contain the length of the actual data plus error info.
* Extract data length.
*/
if (len < sizeof(packet_len)) {
debug("Rx: incomplete packet length\n");
goto err;
}
memcpy(&packet_len, ptr, sizeof(packet_len));
le32_to_cpus(&packet_len);
if (packet_len & RX_STS_ES_) {
debug("Rx: Error header=%#x", packet_len);
goto err;
}
packet_len = ((packet_len & RX_STS_FL_) >> 16);
if (packet_len > len - sizeof(packet_len)) {
debug("Rx: too large packet: %d\n", packet_len);
goto err;
}
*packetp = ptr + sizeof(packet_len);
return packet_len;
err:
usb_ether_advance_rxbuf(ueth, -1);
return -EINVAL;
}
static int smsc95xx_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
{
struct smsc95xx_private *priv = dev_get_priv(dev);
packet_len = ALIGN(packet_len, 4);
usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
return 0;
}
int smsc95xx_write_hwaddr(struct udevice *dev)
{
struct usb_device *udev = dev_get_parentdata(dev);
struct eth_pdata *pdata = dev_get_platdata(dev);
struct smsc95xx_private *priv = dev_get_priv(dev);
return smsc95xx_write_hwaddr_common(udev, priv, pdata->enetaddr);
}
static int smsc95xx_eth_probe(struct udevice *dev)
{
struct smsc95xx_private *priv = dev_get_priv(dev);
struct ueth_data *ueth = &priv->ueth;
return usb_ether_register(dev, ueth, RX_URB_SIZE);
}
static const struct eth_ops smsc95xx_eth_ops = {
.start = smsc95xx_eth_start,
.send = smsc95xx_eth_send,
.recv = smsc95xx_eth_recv,
.free_pkt = smsc95xx_free_pkt,
.stop = smsc95xx_eth_stop,
.write_hwaddr = smsc95xx_write_hwaddr,
};
U_BOOT_DRIVER(smsc95xx_eth) = {
.name = "smsc95xx_eth",
.id = UCLASS_ETH,
.probe = smsc95xx_eth_probe,
.ops = &smsc95xx_eth_ops,
.priv_auto_alloc_size = sizeof(struct smsc95xx_private),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
};
static const struct usb_device_id smsc95xx_eth_id_table[] = {
{ USB_DEVICE(0x05ac, 0x1402) },
{ USB_DEVICE(0x0424, 0xec00) }, /* LAN9512/LAN9514 Ethernet */
{ USB_DEVICE(0x0424, 0x9500) }, /* LAN9500 Ethernet */
{ USB_DEVICE(0x0424, 0x9730) }, /* LAN9730 Ethernet (HSIC) */
{ USB_DEVICE(0x0424, 0x9900) }, /* SMSC9500 USB Ethernet (SAL10) */
{ USB_DEVICE(0x0424, 0x9e00) }, /* LAN9500A Ethernet */
{ } /* Terminating entry */
};
U_BOOT_USB_DEVICE(smsc95xx_eth, smsc95xx_eth_id_table);
#endif

View File

@ -6,6 +6,7 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <usb.h>
#include <dm/device-internal.h>

View File

@ -6,6 +6,7 @@
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <usb.h>
#include <malloc.h>
@ -21,18 +22,29 @@
#define DWC2_STATUS_BUF_SIZE 64
#define DWC2_DATA_BUF_SIZE (64 * 1024)
/* We need doubleword-aligned buffers for DMA transfers */
DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer, DWC2_DATA_BUF_SIZE, 8);
DEFINE_ALIGN_BUFFER(uint8_t, status_buffer, DWC2_STATUS_BUF_SIZE, 8);
#define MAX_DEVICE 16
#define MAX_ENDPOINT 16
static int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
static int root_hub_devnum;
struct dwc2_priv {
#ifdef CONFIG_DM_USB
uint8_t aligned_buffer[DWC2_DATA_BUF_SIZE] __aligned(8);
uint8_t status_buffer[DWC2_STATUS_BUF_SIZE] __aligned(8);
#else
uint8_t *aligned_buffer;
uint8_t *status_buffer;
#endif
int bulk_data_toggle[MAX_DEVICE][MAX_ENDPOINT];
struct dwc2_core_regs *regs;
int root_hub_devnum;
};
static struct dwc2_core_regs *regs =
(struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR;
#ifndef CONFIG_DM_USB
/* We need doubleword-aligned buffers for DMA transfers */
DEFINE_ALIGN_BUFFER(uint8_t, aligned_buffer_addr, DWC2_DATA_BUF_SIZE, 8);
DEFINE_ALIGN_BUFFER(uint8_t, status_buffer_addr, DWC2_STATUS_BUF_SIZE, 8);
static struct dwc2_priv local;
#endif
/*
* DWC2 IP interface
@ -428,7 +440,8 @@ static void dwc_otg_hc_init(struct dwc2_core_regs *regs, uint8_t hc_num,
* DWC2 to USB API interface
*/
/* Direction: In ; Request: Status */
static int dwc_otg_submit_rh_msg_in_status(struct usb_device *dev, void *buffer,
static int dwc_otg_submit_rh_msg_in_status(struct dwc2_core_regs *regs,
struct usb_device *dev, void *buffer,
int txlen, struct devrequest *cmd)
{
uint32_t hprt0 = 0;
@ -602,13 +615,13 @@ static int dwc_otg_submit_rh_msg_in_configuration(struct usb_device *dev,
}
/* Direction: In */
static int dwc_otg_submit_rh_msg_in(struct usb_device *dev,
void *buffer, int txlen,
struct devrequest *cmd)
static int dwc_otg_submit_rh_msg_in(struct dwc2_priv *priv,
struct usb_device *dev, void *buffer,
int txlen, struct devrequest *cmd)
{
switch (cmd->request) {
case USB_REQ_GET_STATUS:
return dwc_otg_submit_rh_msg_in_status(dev, buffer,
return dwc_otg_submit_rh_msg_in_status(priv->regs, dev, buffer,
txlen, cmd);
case USB_REQ_GET_DESCRIPTOR:
return dwc_otg_submit_rh_msg_in_descriptor(dev, buffer,
@ -623,10 +636,12 @@ static int dwc_otg_submit_rh_msg_in(struct usb_device *dev,
}
/* Direction: Out */
static int dwc_otg_submit_rh_msg_out(struct usb_device *dev,
void *buffer, int txlen,
struct devrequest *cmd)
static int dwc_otg_submit_rh_msg_out(struct dwc2_priv *priv,
struct usb_device *dev,
void *buffer, int txlen,
struct devrequest *cmd)
{
struct dwc2_core_regs *regs = priv->regs;
int len = 0;
int stat = 0;
uint16_t bmrtype_breq = cmd->requesttype | (cmd->request << 8);
@ -673,7 +688,7 @@ static int dwc_otg_submit_rh_msg_out(struct usb_device *dev,
}
break;
case (USB_REQ_SET_ADDRESS << 8):
root_hub_devnum = wValue;
priv->root_hub_devnum = wValue;
break;
case (USB_REQ_SET_CONFIGURATION << 8):
break;
@ -690,8 +705,8 @@ static int dwc_otg_submit_rh_msg_out(struct usb_device *dev,
return stat;
}
static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
void *buffer, int txlen,
static int dwc_otg_submit_rh_msg(struct dwc2_priv *priv, struct usb_device *dev,
unsigned long pipe, void *buffer, int txlen,
struct devrequest *cmd)
{
int stat = 0;
@ -702,16 +717,17 @@ static int dwc_otg_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
}
if (cmd->requesttype & USB_DIR_IN)
stat = dwc_otg_submit_rh_msg_in(dev, buffer, txlen, cmd);
stat = dwc_otg_submit_rh_msg_in(priv, dev, buffer, txlen, cmd);
else
stat = dwc_otg_submit_rh_msg_out(dev, buffer, txlen, cmd);
stat = dwc_otg_submit_rh_msg_out(priv, dev, buffer, txlen, cmd);
mdelay(1);
return stat;
}
int wait_for_chhltd(uint32_t *sub, int *toggle, bool ignore_ack)
int wait_for_chhltd(struct dwc2_core_regs *regs, uint32_t *sub, int *toggle,
bool ignore_ack)
{
uint32_t hcint_comp_hlt_ack = DWC2_HCINT_XFERCOMP | DWC2_HCINT_CHHLTD;
struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
@ -751,9 +767,11 @@ static int dwc2_eptype[] = {
DWC2_HCCHAR_EPTYPE_BULK,
};
int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
void *buffer, int len, bool ignore_ack)
int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev,
unsigned long pipe, int *pid, int in, void *buffer, int len,
bool ignore_ack)
{
struct dwc2_core_regs *regs = priv->regs;
struct dwc2_hc_regs *hc_regs = &regs->hc_regs[DWC2_HC_CHANNEL];
int devnum = usb_pipedevice(pipe);
int ep = usb_pipeendpoint(pipe);
@ -802,10 +820,12 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
(*pid << DWC2_HCTSIZ_PID_OFFSET),
&hc_regs->hctsiz);
if (!in)
memcpy(aligned_buffer, (char *)buffer + done, len);
if (!in) {
memcpy(priv->aligned_buffer, (char *)buffer + done,
len);
}
writel(phys_to_bus((unsigned long)aligned_buffer),
writel(phys_to_bus((unsigned long)priv->aligned_buffer),
&hc_regs->hcdma);
/* Set host channel enable after all other setup is complete. */
@ -814,13 +834,13 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
(1 << DWC2_HCCHAR_MULTICNT_OFFSET) |
DWC2_HCCHAR_CHEN);
ret = wait_for_chhltd(&sub, pid, ignore_ack);
ret = wait_for_chhltd(regs, &sub, pid, ignore_ack);
if (ret)
break;
if (in) {
xfer_len -= sub;
memcpy(buffer + done, aligned_buffer, xfer_len);
memcpy(buffer + done, priv->aligned_buffer, xfer_len);
if (sub)
stop_transfer = 1;
}
@ -839,43 +859,45 @@ int chunk_msg(struct usb_device *dev, unsigned long pipe, int *pid, int in,
}
/* U-Boot USB transmission interface */
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int len)
int _submit_bulk_msg(struct dwc2_priv *priv, struct usb_device *dev,
unsigned long pipe, void *buffer, int len)
{
int devnum = usb_pipedevice(pipe);
int ep = usb_pipeendpoint(pipe);
if (devnum == root_hub_devnum) {
if (devnum == priv->root_hub_devnum) {
dev->status = 0;
return -EINVAL;
}
return chunk_msg(dev, pipe, &bulk_data_toggle[devnum][ep],
return chunk_msg(priv, dev, pipe, &priv->bulk_data_toggle[devnum][ep],
usb_pipein(pipe), buffer, len, true);
}
int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int len, struct devrequest *setup)
static int _submit_control_msg(struct dwc2_priv *priv, struct usb_device *dev,
unsigned long pipe, void *buffer, int len,
struct devrequest *setup)
{
int devnum = usb_pipedevice(pipe);
int pid, ret, act_len;
/* For CONTROL endpoint pid should start with DATA1 */
int status_direction;
if (devnum == root_hub_devnum) {
if (devnum == priv->root_hub_devnum) {
dev->status = 0;
dev->speed = USB_SPEED_HIGH;
return dwc_otg_submit_rh_msg(dev, pipe, buffer, len, setup);
return dwc_otg_submit_rh_msg(priv, dev, pipe, buffer, len,
setup);
}
pid = DWC2_HC_PID_SETUP;
ret = chunk_msg(dev, pipe, &pid, 0, setup, 8, true);
ret = chunk_msg(priv, dev, pipe, &pid, 0, setup, 8, true);
if (ret)
return ret;
if (buffer) {
pid = DWC2_HC_PID_DATA1;
ret = chunk_msg(dev, pipe, &pid, usb_pipein(pipe), buffer,
ret = chunk_msg(priv, dev, pipe, &pid, usb_pipein(pipe), buffer,
len, false);
if (ret)
return ret;
@ -891,8 +913,8 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
status_direction = 0;
pid = DWC2_HC_PID_DATA1;
ret = chunk_msg(dev, pipe, &pid, status_direction, status_buffer, 0,
false);
ret = chunk_msg(priv, dev, pipe, &pid, status_direction,
priv->status_buffer, 0, false);
if (ret)
return ret;
@ -901,8 +923,8 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
return 0;
}
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int len, int interval)
int _submit_int_msg(struct dwc2_priv *priv, struct usb_device *dev,
unsigned long pipe, void *buffer, int len, int interval)
{
unsigned long timeout;
int ret;
@ -915,24 +937,18 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
printf("Timeout poll on interrupt endpoint\n");
return -ETIMEDOUT;
}
ret = submit_bulk_msg(dev, pipe, buffer, len);
ret = _submit_bulk_msg(priv, dev, pipe, buffer, len);
if (ret != -EAGAIN)
return ret;
}
}
/* U-Boot USB control interface */
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
static int dwc2_init_common(struct dwc2_priv *priv)
{
struct dwc2_core_regs *regs = priv->regs;
uint32_t snpsid;
int i, j;
root_hub_devnum = 0;
/* board dependant init */
if (board_usb_init(index, USB_INIT_HOST))
return -1;
snpsid = readl(&regs->gsnpsid);
printf("Core Release: %x.%03x\n", snpsid >> 12 & 0xf, snpsid & 0xfff);
@ -956,18 +972,149 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
for (i = 0; i < MAX_DEVICE; i++) {
for (j = 0; j < MAX_ENDPOINT; j++)
bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0;
priv->bulk_data_toggle[i][j] = DWC2_HC_PID_DATA0;
}
return 0;
}
int usb_lowlevel_stop(int index)
static void dwc2_uninit_common(struct dwc2_core_regs *regs)
{
/* Put everything in reset. */
clrsetbits_le32(&regs->hprt0, DWC2_HPRT0_PRTENA |
DWC2_HPRT0_PRTCONNDET | DWC2_HPRT0_PRTENCHNG |
DWC2_HPRT0_PRTOVRCURRCHNG,
DWC2_HPRT0_PRTRST);
}
#ifndef CONFIG_DM_USB
int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int len, struct devrequest *setup)
{
return _submit_control_msg(&local, dev, pipe, buffer, len, setup);
}
int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int len)
{
return _submit_bulk_msg(&local, dev, pipe, buffer, len);
}
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
int len, int interval)
{
return _submit_int_msg(&local, dev, pipe, buffer, len, interval);
}
/* U-Boot USB control interface */
int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
{
struct dwc2_priv *priv = &local;
memset(priv, '\0', sizeof(*priv));
priv->root_hub_devnum = 0;
priv->regs = (struct dwc2_core_regs *)CONFIG_USB_DWC2_REG_ADDR;
priv->aligned_buffer = aligned_buffer_addr;
priv->status_buffer = status_buffer_addr;
/* board-dependant init */
if (board_usb_init(index, USB_INIT_HOST))
return -1;
return dwc2_init_common(priv);
}
int usb_lowlevel_stop(int index)
{
dwc2_uninit_common(local.regs);
return 0;
}
#endif
#ifdef CONFIG_DM_USB
static int dwc2_submit_control_msg(struct udevice *dev, struct usb_device *udev,
unsigned long pipe, void *buffer, int length,
struct devrequest *setup)
{
struct dwc2_priv *priv = dev_get_priv(dev);
debug("%s: dev='%s', udev=%p, udev->dev='%s', portnr=%d\n", __func__,
dev->name, udev, udev->dev->name, udev->portnr);
return _submit_control_msg(priv, udev, pipe, buffer, length, setup);
}
static int dwc2_submit_bulk_msg(struct udevice *dev, struct usb_device *udev,
unsigned long pipe, void *buffer, int length)
{
struct dwc2_priv *priv = dev_get_priv(dev);
debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
return _submit_bulk_msg(priv, udev, pipe, buffer, length);
}
static int dwc2_submit_int_msg(struct udevice *dev, struct usb_device *udev,
unsigned long pipe, void *buffer, int length,
int interval)
{
struct dwc2_priv *priv = dev_get_priv(dev);
debug("%s: dev='%s', udev=%p\n", __func__, dev->name, udev);
return _submit_int_msg(priv, udev, pipe, buffer, length, interval);
}
static int dwc2_usb_ofdata_to_platdata(struct udevice *dev)
{
struct dwc2_priv *priv = dev_get_priv(dev);
fdt_addr_t addr;
addr = dev_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->regs = (struct dwc2_core_regs *)addr;
return 0;
}
static int dwc2_usb_probe(struct udevice *dev)
{
struct dwc2_priv *priv = dev_get_priv(dev);
return dwc2_init_common(priv);
}
static int dwc2_usb_remove(struct udevice *dev)
{
struct dwc2_priv *priv = dev_get_priv(dev);
dwc2_uninit_common(priv->regs);
return 0;
}
struct dm_usb_ops dwc2_usb_ops = {
.control = dwc2_submit_control_msg,
.bulk = dwc2_submit_bulk_msg,
.interrupt = dwc2_submit_int_msg,
};
static const struct udevice_id dwc2_usb_ids[] = {
{ .compatible = "brcm,bcm2835-usb" },
{ }
};
U_BOOT_DRIVER(usb_dwc2) = {
.name = "dwc2_exynos",
.id = UCLASS_USB,
.of_match = dwc2_usb_ids,
.ofdata_to_platdata = dwc2_usb_ofdata_to_platdata,
.probe = dwc2_usb_probe,
.remove = dwc2_usb_remove,
.ops = &dwc2_usb_ops,
.priv_auto_alloc_size = sizeof(struct dwc2_priv),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
};
#endif

View File

@ -240,3 +240,5 @@ config VIDEO_TEGRA124
HDMI. At present only eDP is supported by U-Boot. This option
enables this support which can be used on devices which
have an eDP display connected.
source "drivers/video/bridge/Kconfig"

View File

@ -51,6 +51,7 @@ obj-$(CONFIG_VIDEO_VESA) += vesa_fb.o
obj-$(CONFIG_FORMIKE) += formike.o
obj-$(CONFIG_LG4573) += lg4573.o
obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
obj-$(CONFIG_VIDEO_PARADE) += parade.o
obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
obj-y += bridge/

View File

@ -0,0 +1,27 @@
config VIDEO_BRIDGE
bool "Support video bridges"
depends on DM
help
Some platforms use video bridges to convert from one output to
another. For example, where the SoC only supports eDP and the LCD
requires LVDS, an eDP->LVDS bridge chip can be used to provide the
necessary conversion. This option enables support for these devices.
config VIDEO_BRIDGE_PARADE_PS862X
bool "Support Parade PS862X DP->LVDS bridge"
depends on VIDEO_BRIDGE
help
The Parade PS8622 and PS8625 are DisplayPort-to-LVDS (Low voltage
differential signalling) converters. They enable an LVDS LCD panel
to be connected to an eDP output device such as an SoC that lacks
LVDS capability, or where LVDS requires too many signals to route
on the PCB. Setup parameters are provided in the device tree.
config VIDEO_BRIDGE_NXP_PTN3460
bool "Support NXP PTN3460 DP->LVDS bridge"
depends on VIDEO_BRIDGE
help
The NXP PTN3460 is a DisplayPort-to-LVDS (Low voltage differential
signalling) converter. It enables an LVDS LCD panel to be connected
to an eDP output device such as an SoC that lacks LVDS capability,
or where LVDS requires too many signals to route on the PCB.

View File

@ -0,0 +1,9 @@
#
# Copyright (C) 2015 Google, Inc
# Written by Simon Glass <sjg@chromium.org>
#
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_VIDEO_BRIDGE) += video-bridge-uclass.o
obj-$(CONFIG_VIDEO_BRIDGE_PARADE_PS862X) += ps862x.o
obj-$(CONFIG_VIDEO_BRIDGE_NXP_PTN3460) += ptn3460.o

View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
#include <video_bridge.h>
#include <power/regulator.h>
DECLARE_GLOBAL_DATA_PTR;
/*
* Initialisation of the chip is a process of writing certain values into
* certain registers over i2c bus. The chip in fact responds to a range of
* addresses on the i2c bus, so for each written value three parameters are
* required: i2c address, register address and the actual value.
*
* The base address is derived from the device tree, but oddly the chip
* responds on several addresses with different register sets for each.
*/
/**
* ps8622_write() Write a PS8622 eDP bridge i2c register
*
* @param dev I2C device
* @param addr_off offset from the i2c base address for ps8622
* @param reg_addr register address to write
* @param value value to be written
* @return 0 on success, non-0 on failure
*/
static int ps8622_write(struct udevice *dev, unsigned addr_off,
unsigned char reg_addr, unsigned char value)
{
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
uint8_t buf[2];
struct i2c_msg msg;
int ret;
msg.addr = chip->chip_addr + addr_off;
msg.flags = 0;
buf[0] = reg_addr;
buf[1] = value;
msg.buf = buf;
msg.len = 2;
ret = dm_i2c_xfer(dev, &msg, 1);
if (ret) {
debug("%s: write failed, reg=%#x, value=%#x, ret=%d\n",
__func__, reg_addr, value, ret);
return ret;
}
return 0;
}
static int ps8622_set_backlight(struct udevice *dev, int percent)
{
int level = percent * 255 / 100;
debug("%s: level=%d\n", __func__, level);
return ps8622_write(dev, 0x01, 0xa7, level);
}
static int ps8622_attach(struct udevice *dev)
{
const uint8_t *params;
struct udevice *reg;
int ret, i, len;
debug("%s: %s\n", __func__, dev->name);
/* set the LDO providing the 1.2V rail to the Parade bridge */
ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
"power-supply", &reg);
if (!ret) {
ret = regulator_autoset(reg);
} else if (ret != -ENOENT) {
debug("%s: Failed to enable power: ret=%d\n", __func__, ret);
return ret;
}
ret = video_bridge_set_active(dev, true);
if (ret)
return ret;
params = fdt_getprop(gd->fdt_blob, dev->of_offset, "parade,regs", &len);
if (!params || len % 3) {
debug("%s: missing/invalid params=%p, len=%x\n", __func__,
params, len);
return -EINVAL;
}
/* need to wait 20ms after power on before doing I2C writes */
mdelay(20);
for (i = 0; i < len; i += 3) {
ret = ps8622_write(dev, params[i + 0], params[i + 1],
params[i + 2]);
if (ret)
return ret;
}
return 0;
}
static int ps8622_probe(struct udevice *dev)
{
debug("%s\n", __func__);
if (device_get_uclass_id(dev->parent) != UCLASS_I2C)
return -EPROTONOSUPPORT;
return 0;
}
struct video_bridge_ops ps8622_ops = {
.attach = ps8622_attach,
.set_backlight = ps8622_set_backlight,
};
static const struct udevice_id ps8622_ids[] = {
{ .compatible = "parade,ps8622", },
{ .compatible = "parade,ps8625", },
{ }
};
U_BOOT_DRIVER(parade_ps8622) = {
.name = "parade_ps8622",
.id = UCLASS_VIDEO_BRIDGE,
.of_match = ps8622_ids,
.probe = ps8622_probe,
.ops = &ps8622_ops,
};

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <video_bridge.h>
static int ptn3460_attach(struct udevice *dev)
{
int ret;
debug("%s: %s\n", __func__, dev->name);
ret = video_bridge_set_active(dev, true);
if (ret)
return ret;
return 0;
}
struct video_bridge_ops ptn3460_ops = {
.attach = ptn3460_attach,
};
static const struct udevice_id ptn3460_ids[] = {
{ .compatible = "nxp,ptn3460", },
{ }
};
U_BOOT_DRIVER(parade_ptn3460) = {
.name = "nmp_ptn3460",
.id = UCLASS_VIDEO_BRIDGE,
.of_match = ptn3460_ids,
.ops = &ptn3460_ops,
};

View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2015 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <video_bridge.h>
int video_bridge_set_backlight(struct udevice *dev, int percent)
{
struct video_bridge_ops *ops = video_bridge_get_ops(dev);
if (!ops->set_backlight)
return -ENOSYS;
return ops->set_backlight(dev, percent);
}
int video_bridge_attach(struct udevice *dev)
{
struct video_bridge_ops *ops = video_bridge_get_ops(dev);
if (!ops->attach)
return -ENOSYS;
return ops->attach(dev);
}
int video_bridge_check_attached(struct udevice *dev)
{
struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
struct video_bridge_ops *ops = video_bridge_get_ops(dev);
int ret;
if (!ops->check_attached) {
ret = dm_gpio_get_value(&uc_priv->hotplug);
return ret > 0 ? 0 : ret == 0 ? -ENOTCONN : ret;
}
return ops->check_attached(dev);
}
static int video_bridge_pre_probe(struct udevice *dev)
{
struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
int ret;
debug("%s\n", __func__);
ret = gpio_request_by_name(dev, "sleep-gpios", 0,
&uc_priv->sleep, GPIOD_IS_OUT);
if (ret) {
debug("%s: Could not decode sleep-gpios (%d)\n", __func__, ret);
return ret;
}
/*
* Drop this for now as we do not have driver model pinctrl support
*
* ret = dm_gpio_set_pull(&uc_priv->sleep, GPIO_PULL_NONE);
* if (ret) {
* debug("%s: Could not set sleep pull value\n", __func__);
* return ret;
* }
*/
ret = gpio_request_by_name(dev, "reset-gpios", 0, &uc_priv->reset,
GPIOD_IS_OUT);
if (ret) {
debug("%s: Could not decode reset-gpios (%d)\n", __func__, ret);
return ret;
}
/*
* Drop this for now as we do not have driver model pinctrl support
*
* ret = dm_gpio_set_pull(&uc_priv->reset, GPIO_PULL_NONE);
* if (ret) {
* debug("%s: Could not set reset pull value\n", __func__);
* return ret;
* }
*/
ret = gpio_request_by_name(dev, "hotplug-gpios", 0, &uc_priv->hotplug,
GPIOD_IS_IN);
if (ret && ret != -ENOENT) {
debug("%s: Could not decode hotplug (%d)\n", __func__, ret);
return ret;
}
return 0;
}
int video_bridge_set_active(struct udevice *dev, bool active)
{
struct video_bridge_priv *uc_priv = dev_get_uclass_priv(dev);
int ret;
debug("%s: %d\n", __func__, active);
ret = dm_gpio_set_value(&uc_priv->sleep, !active);
if (ret)
return ret;
if (active) {
ret = dm_gpio_set_value(&uc_priv->reset, true);
if (ret)
return ret;
udelay(10);
ret = dm_gpio_set_value(&uc_priv->reset, false);
}
return ret;
}
UCLASS_DRIVER(video_bridge) = {
.id = UCLASS_VIDEO_BRIDGE,
.name = "video_bridge",
.per_device_auto_alloc_size = sizeof(struct video_bridge_priv),
.pre_probe = video_bridge_pre_probe,
};

View File

@ -22,8 +22,6 @@
DECLARE_GLOBAL_DATA_PTR;
static struct exynos_dp_platform_data *dp_pd;
void __exynos_set_dp_phy(unsigned int onoff)
{
}
@ -851,7 +849,6 @@ static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info)
return ret;
}
#ifdef CONFIG_OF_CONTROL
int exynos_dp_parse_dt(const void *blob, struct edp_device_info *edp_info)
{
unsigned int node = fdtdec_next_compatible(blob, 0,
@ -905,7 +902,6 @@ int exynos_dp_parse_dt(const void *blob, struct edp_device_info *edp_info)
"samsung,color-depth", 0);
return 0;
}
#endif
unsigned int exynos_init_dp(void)
{
@ -918,16 +914,8 @@ unsigned int exynos_init_dp(void)
return -EFAULT;
}
#ifdef CONFIG_OF_CONTROL
if (exynos_dp_parse_dt(gd->fdt_blob, edp_info))
debug("unable to parse DP DT node\n");
#else
edp_info = dp_pd->edp_dev_info;
if (edp_info == NULL) {
debug("failed to get edp_info data.\n");
return -EFAULT;
}
#endif
exynos_dp_set_base_addr();
@ -967,17 +955,7 @@ unsigned int exynos_init_dp(void)
return ret;
}
printf("Exynos DP init done\n");
debug("Exynos DP init done\n");
return ret;
}
void exynos_set_dp_platform_data(struct exynos_dp_platform_data *pd)
{
if (pd == NULL) {
debug("pd is NULL\n");
return;
}
dp_pd = pd;
}

View File

@ -823,7 +823,7 @@ int exynos_dp_read_bytes_from_i2c(unsigned int device_addr,
reg = readl(&dp_regs->aux_rx_comm);
if (reg == AUX_RX_COMM_AUX_DEFER ||
reg == AUX_RX_COMM_I2C_DEFER) {
printf("DP Defer: %d\n\n", reg);
printf("DP Defer: %d\n", reg);
defer = 1;
}
}

View File

@ -1,231 +0,0 @@
/*
* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* This file is a driver for Parade dP<->LVDS bridges. The original submission
* is for the ps8625 chip.
*/
#include <config.h>
#include <common.h>
#include <i2c.h>
#include <fdtdec.h>
#include <asm/gpio.h>
/*
* Initialization of the chip is a process of writing certaing values into
* certain registers over i2c bus. The chip in fact responds to a range of
* addresses on the i2c bus, so for each written value three parameters are
* required: i2c address, register address and the actual value.
*
* The base address is derived from the device tree, only address offset is
* stored in the table below.
*/
/**
* struct reg_data() - data for a parade register write
*
* @addr_off offset from the i2c base address for parade
* @reg_addr register address to write
* @value value to be written
*/
struct reg_data {
uint8_t addr_off;
uint8_t reg;
uint8_t value;
} _packed;
#define END_OF_TABLE 0xff /* Ficticious offset */
static const struct reg_data parade_values[] = {
{0x02, 0xa1, 0x01}, /* HPD low */
/*
* SW setting
* [1:0] SW output 1.2V voltage is lower to 96%
*/
{0x04, 0x14, 0x01},
/*
* RCO SS setting
* [5:4] = b01 0.5%, b10 1%, b11 1.5%
*/
{0x04, 0xe3, 0x20},
{0x04, 0xe2, 0x80}, /* [7] RCO SS enable */
/*
* RPHY Setting
* [3:2] CDR tune wait cycle before
* measure for fine tune b00: 1us,
* 01: 0.5us, 10:2us, 11:4us.
*/
{0x04, 0x8a, 0x0c},
{0x04, 0x89, 0x08}, /* [3] RFD always on */
/*
* CTN lock in/out:
* 20000ppm/80000ppm. Lock out 2
* times.
*/
{0x04, 0x71, 0x2d},
/*
* 2.7G CDR settings
* NOF=40LSB for HBR CDR setting
*/
{0x04, 0x7d, 0x07},
{0x04, 0x7b, 0x00}, /* [1:0] Fmin=+4bands */
{0x04, 0x7a, 0xfd}, /* [7:5] DCO_FTRNG=+-40% */
/*
* 1.62G CDR settings
* [5:2]NOF=64LSB [1:0]DCO scale is 2/5
*/
{0x04, 0xc0, 0x12},
{0x04, 0xc1, 0x92}, /* Gitune=-37% */
{0x04, 0xc2, 0x1c}, /* Fbstep=100% */
{0x04, 0x32, 0x80}, /* [7] LOS signal disable */
/*
* RPIO Setting
* [7:4] LVDS driver bias current :
* 75% (250mV swing)
*/
{0x04, 0x00, 0xb0},
/*
* [7:6] Right-bar GPIO output strength is 8mA
*/
{0x04, 0x15, 0x40},
/* EQ Training State Machine Setting */
{0x04, 0x54, 0x10}, /* RCO calibration start */
/* [4:0] MAX_LANE_COUNT set to one lane */
{0x01, 0x02, 0x81},
/* [4:0] LANE_COUNT_SET set to one lane */
{0x01, 0x21, 0x81},
{0x00, 0x52, 0x20},
{0x00, 0xf1, 0x03}, /* HPD CP toggle enable */
{0x00, 0x62, 0x41},
/* Counter number, add 1ms counter delay */
{0x00, 0xf6, 0x01},
/*
* [6]PWM function control by
* DPCD0040f[7], default is PWM
* block always works.
*/
{0x00, 0x77, 0x06},
/*
* 04h Adjust VTotal tolerance to
* fix the 30Hz no display issue
*/
{0x00, 0x4c, 0x04},
/* DPCD00400='h00, Parade OUI = 'h001cf8 */
{0x01, 0xc0, 0x00},
{0x01, 0xc1, 0x1c}, /* DPCD00401='h1c */
{0x01, 0xc2, 0xf8}, /* DPCD00402='hf8 */
/*
* DPCD403~408 = ASCII code
* D2SLV5='h4432534c5635
*/
{0x01, 0xc3, 0x44},
{0x01, 0xc4, 0x32}, /* DPCD404 */
{0x01, 0xc5, 0x53}, /* DPCD405 */
{0x01, 0xc6, 0x4c}, /* DPCD406 */
{0x01, 0xc7, 0x56}, /* DPCD407 */
{0x01, 0xc8, 0x35}, /* DPCD408 */
/*
* DPCD40A, Initial Code major revision
* '01'
*/
{0x01, 0xca, 0x01},
/* DPCD40B, Initial Code minor revision '05' */
{0x01, 0xcb, 0x05},
/* DPCD720, Select internal PWM */
{0x01, 0xa5, 0xa0},
/*
* FFh for 100% PWM of brightness, 0h for 0%
* brightness
*/
{0x01, 0xa7, 0xff},
/*
* Set LVDS output as 6bit-VESA mapping,
* single LVDS channel
*/
{0x01, 0xcc, 0x13},
/* Enable SSC set by register */
{0x02, 0xb1, 0x20},
/*
* Set SSC enabled and +/-1% central
* spreading
*/
{0x04, 0x10, 0x16},
/* MPU Clock source: LC => RCO */
{0x04, 0x59, 0x60},
{0x04, 0x54, 0x14}, /* LC -> RCO */
{0x02, 0xa1, 0x91}, /* HPD high */
{END_OF_TABLE}
};
/**
* Write values table into the Parade eDP bridge
*
* @return 0 on success, non-0 on failure
*/
static int parade_write_regs(int base_addr, const struct reg_data *table)
{
int ret = 0;
while (!ret && (table->addr_off != END_OF_TABLE)) {
ret = i2c_write(base_addr + table->addr_off,
table->reg, 1,
(uint8_t *)&table->value,
sizeof(table->value));
table++;
}
return ret;
}
int parade_init(const void *blob)
{
struct gpio_desc rst_gpio;
struct gpio_desc slp_gpio;
int bus, old_bus;
int parent;
int node;
int addr;
int ret;
node = fdtdec_next_compatible(blob, 0, COMPAT_PARADE_PS8625);
if (node < 0)
return 0;
parent = fdt_parent_offset(blob, node);
if (parent < 0) {
debug("%s: Could not find parent i2c node\n", __func__);
return -1;
}
addr = fdtdec_get_int(blob, node, "reg", -1);
if (addr < 0) {
debug("%s: Could not find i2c address\n", __func__);
return -1;
}
gpio_request_by_name_nodev(blob, node, "sleep-gpio", 0, &slp_gpio,
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
mdelay(10);
gpio_request_by_name_nodev(blob, node, "reset-gpio", 0, &rst_gpio,
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
bus = i2c_get_bus_num_fdt(parent);
old_bus = i2c_get_bus_num();
debug("%s: Using i2c bus %d\n", __func__, bus);
/*
* TODO(sjg@chromium.org): Hmmm we seem to need some sort of delay
* here.
*/
mdelay(40);
i2c_set_bus_num(bus);
ret = parade_write_regs(addr, parade_values);
i2c_set_bus_num(old_bus);
return ret;
}

View File

@ -92,7 +92,7 @@ void lcd_ctrl_init(void *lcdbase)
/* Enable flushing after LCD writes if requested */
lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH);
debug("LCD frame buffer at %08X\n", disp_config->frame_buffer);
debug("LCD frame buffer at %pa\n", &disp_config->frame_buffer);
}
ulong calc_fbsize(void)

View File

@ -13,6 +13,7 @@
"fdtfile=exynos5250-arndale.dtb\0"
#include "exynos5250-common.h"
#include <configs/exynos5-common.h>
/* SD/MMC configuration */
#define CONFIG_SUPPORT_EMMC_BOOT
@ -20,15 +21,6 @@
/* allow to overwrite serial and ethaddr */
#define CONFIG_ENV_OVERWRITE
/* USB */
#define CONFIG_USB_EHCI
#define CONFIG_USB_EHCI_EXYNOS
#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 3
#define CONFIG_USB_HOST_ETHER
#define CONFIG_USB_ETHER_ASIX
#define CONFIG_USB_ETHER_ASIX88179
/* MMC SPL */
#define CONFIG_EXYNOS_SPL
@ -36,9 +28,6 @@
#define CONFIG_SYS_PROMPT "ARNDALE # "
#define CONFIG_DEFAULT_CONSOLE "console=ttySAC2,115200n8\0"
#define CONFIG_NR_DRAM_BANKS 8
#define SDRAM_BANK_SIZE (256UL << 20UL) /* 256 MB */
#define CONFIG_IDENT_STRING " for ARNDALE"
#define CONFIG_ENV_IS_IN_MMC
@ -49,6 +38,7 @@
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_IRAM_STACK
/* PMIC */
#define CONFIG_POWER
#define CONFIG_PMIC
#define CONFIG_POWER_I2C
@ -60,4 +50,8 @@
/* The PERIPHBASE in the CBAR register is wrong on the Arndale, so override it */
#define CONFIG_ARM_GIC_BASE_ADDRESS 0x10480000
/* Power */
#define CONFIG_POWER
#define CONFIG_POWER_I2C
#endif /* __CONFIG_H */

View File

@ -67,6 +67,8 @@
#define CONFIG_SPL_LIBCOMMON_SUPPORT
#define CONFIG_SPL_GPIO_SUPPORT
#define CONFIG_SPL_SERIAL_SUPPORT
#define CONFIG_SPL_LIBGENERIC_SUPPORT
/* specific .lds file */
#define CONFIG_SPL_LDSCRIPT "board/samsung/common/exynos-uboot-spl.lds"
@ -126,10 +128,6 @@
#define SPI_FLASH_UBOOT_POS (CONFIG_SEC_FW_SIZE + CONFIG_BL1_SIZE)
/* I2C */
/* TODO(sjg@chromium.org): Move these two options to Kconfig */
#define CONFIG_DM_I2C
#define CONFIG_DM_I2C_COMPAT
#define CONFIG_CMD_I2C
#define CONFIG_SYS_I2C_S3C24X0
#define CONFIG_SYS_I2C_S3C24X0_SPEED 100000 /* 100 Kbps */
@ -145,14 +143,8 @@
#define CONFIG_SPI_FLASH_GIGADEVICE
#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0
#define CONFIG_SF_DEFAULT_SPEED 50000000
#define EXYNOS5_SPI_NUM_CONTROLLERS 5
#define CONFIG_OF_SPI
#endif
/* Power */
#define CONFIG_POWER
#define CONFIG_POWER_I2C
#ifdef CONFIG_ENV_IS_IN_SPI_FLASH
#define CONFIG_ENV_SPI_MODE SPI_MODE_0
#define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE
@ -200,7 +192,6 @@
#define CONFIG_FIT
#define CONFIG_FIT_BEST_MATCH
#define BOOT_TARGET_DEVICES(func) \
func(MMC, mmc, 1) \
func(MMC, mmc, 0) \

View File

@ -16,12 +16,23 @@
"stdout=serial,lcd\0" \
"stderr=serial,lcd\0"
#include "exynos5-common.h"
#define CONFIG_EXYNOS5_DT
/* PMIC */
#define CONFIG_POWER
#define CONFIG_POWER_I2C
#define CONFIG_POWER_TPS65090
#define CONFIG_ENV_IS_IN_SPI_FLASH
#define CONFIG_ENV_SPI_BASE 0x12D30000
#define FLASH_SIZE (4 << 20)
#define CONFIG_ENV_OFFSET (FLASH_SIZE - CONFIG_ENV_SECT_SIZE)
#define CONFIG_SPI_BOOTING
#define CONFIG_BOARD_COMMON
/* Display */
#define CONFIG_LCD
#ifdef CONFIG_LCD
#define CONFIG_EXYNOS_FB
#define CONFIG_EXYNOS_DP
#define LCD_BPP LCD_COLOR16
#endif
/* Enable keyboard */
#define CONFIG_KEYBOARD

Some files were not shown because too many files have changed in this diff Show More