diff options
86 files changed, 3917 insertions, 310 deletions
diff --git a/arch/arm/dts/armada-38x-controlcenterdc.dts b/arch/arm/dts/armada-38x-controlcenterdc.dts index 896f8ae66d..2cc996876a 100644 --- a/arch/arm/dts/armada-38x-controlcenterdc.dts +++ b/arch/arm/dts/armada-38x-controlcenterdc.dts @@ -92,14 +92,14 @@ spi-flash@0 { #address-cells = <1>; #size-cells = <1>; - compatible = "n25q016a"; + compatible = "n25q016a", "spi-flash"; reg = <0>; /* Chip select 0 */ spi-max-frequency = <108000000>; }; spi-flash@1 { #address-cells = <1>; #size-cells = <1>; - compatible = "n25q128a11"; + compatible = "n25q128a11", "spi-flash"; reg = <1>; /* Chip select 1 */ spi-max-frequency = <108000000>; u-boot,dm-pre-reloc; diff --git a/arch/arm/dts/meson-gx.dtsi b/arch/arm/dts/meson-gx.dtsi index 738ed689ff..4ee2e79514 100644 --- a/arch/arm/dts/meson-gx.dtsi +++ b/arch/arm/dts/meson-gx.dtsi @@ -211,32 +211,39 @@ #size-cells = <2>; ranges; - cbus: cbus@c1100000 { + cbus: bus@c1100000 { compatible = "simple-bus"; reg = <0x0 0xc1100000 0x0 0x100000>; #address-cells = <2>; #size-cells = <2>; ranges = <0x0 0x0 0x0 0xc1100000 0x0 0x100000>; + gpio_intc: interrupt-controller@9880 { + compatible = "amlogic,meson-gpio-intc"; + reg = <0x0 0x9880 0x0 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>; + status = "disabled"; + }; + reset: reset-controller@4404 { compatible = "amlogic,meson-gx-reset", "amlogic,meson-gxbb-reset"; - reg = <0x0 0x04404 0x0 0x20>; + reg = <0x0 0x04404 0x0 0x9c>; #reset-cells = <1>; }; uart_A: serial@84c0 { - compatible = "amlogic,meson-uart"; - reg = <0x0 0x84c0 0x0 0x14>; + compatible = "amlogic,meson-gx-uart"; + reg = <0x0 0x84c0 0x0 0x18>; interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; status = "disabled"; }; uart_B: serial@84dc { - compatible = "amlogic,meson-uart"; - reg = <0x0 0x84dc 0x0 0x14>; + compatible = "amlogic,meson-gx-uart"; + reg = <0x0 0x84dc 0x0 0x18>; interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; status = "disabled"; }; @@ -279,10 +286,9 @@ }; uart_C: serial@8700 { - compatible = "amlogic,meson-uart"; - reg = <0x0 0x8700 0x0 0x14>; + compatible = "amlogic,meson-gx-uart"; + reg = <0x0 0x8700 0x0 0x18>; interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; status = "disabled"; }; @@ -360,33 +366,53 @@ }; }; - aobus: aobus@c8100000 { + aobus: bus@c8100000 { compatible = "simple-bus"; reg = <0x0 0xc8100000 0x0 0x100000>; #address-cells = <2>; #size-cells = <2>; ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>; - clkc_AO: clock-controller@040 { - compatible = "amlogic,gx-aoclkc", "amlogic,gxbb-aoclkc"; - reg = <0x0 0x00040 0x0 0x4>; - #clock-cells = <1>; - #reset-cells = <1>; + sysctrl_AO: sys-ctrl@0 { + compatible = "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd"; + reg = <0x0 0x0 0x0 0x100>; + + pwrc_vpu: power-controller-vpu { + compatible = "amlogic,meson-gx-pwrc-vpu"; + #power-domain-cells = <0>; + amlogic,hhi-sysctrl = <&sysctrl>; + }; + + clkc_AO: clock-controller { + compatible = "amlogic,meson-gx-aoclkc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + }; + + cec_AO: cec@100 { + compatible = "amlogic,meson-gx-ao-cec"; + reg = <0x0 0x00100 0x0 0x14>; + interrupts = <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>; + }; + + sec_AO: ao-secure@140 { + compatible = "amlogic,meson-gx-ao-secure", "syscon"; + reg = <0x0 0x140 0x0 0x140>; + amlogic,has-chip-id; }; uart_AO: serial@4c0 { - compatible = "amlogic,meson-uart"; - reg = <0x0 0x004c0 0x0 0x14>; + compatible = "amlogic,meson-gx-uart", "amlogic,meson-ao-uart"; + reg = <0x0 0x004c0 0x0 0x18>; interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; status = "disabled"; }; uart_AO_B: serial@4e0 { - compatible = "amlogic,meson-uart"; - reg = <0x0 0x004e0 0x0 0x14>; + compatible = "amlogic,meson-gx-uart", "amlogic,meson-ao-uart"; + reg = <0x0 0x004e0 0x0 0x18>; interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>; - clocks = <&xtal>; status = "disabled"; }; @@ -427,19 +453,24 @@ }; }; - hiubus: hiubus@c883c000 { + hiubus: bus@c883c000 { compatible = "simple-bus"; reg = <0x0 0xc883c000 0x0 0x2000>; #address-cells = <2>; #size-cells = <2>; ranges = <0x0 0x0 0x0 0xc883c000 0x0 0x2000>; + sysctrl: system-controller@0 { + compatible = "amlogic,meson-gx-hhi-sysctrl", "syscon", "simple-mfd"; + reg = <0 0 0 0x400>; + }; + mailbox: mailbox@404 { compatible = "amlogic,meson-gx-mhu", "amlogic,meson-gxbb-mhu"; reg = <0 0x404 0 0x4c>; - interrupts = <0 208 IRQ_TYPE_EDGE_RISING>, - <0 209 IRQ_TYPE_EDGE_RISING>, - <0 210 IRQ_TYPE_EDGE_RISING>; + interrupts = <GIC_SPI 208 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 209 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 210 IRQ_TYPE_EDGE_RISING>; #mbox-cells = <1>; }; }; @@ -448,7 +479,7 @@ compatible = "amlogic,meson-gx-dwmac", "amlogic,meson-gxbb-dwmac", "snps,dwmac"; reg = <0x0 0xc9410000 0x0 0x10000 0x0 0xc8834540 0x0 0x4>; - interrupts = <0 8 1>; + interrupts = <GIC_SPI 8 IRQ_TYPE_EDGE_RISING>; interrupt-names = "macirq"; status = "disabled"; }; diff --git a/arch/arm/dts/meson-gxbb-odroidc2.dts b/arch/arm/dts/meson-gxbb-odroidc2.dts index d147c853ab..ee4ada61c5 100644 --- a/arch/arm/dts/meson-gxbb-odroidc2.dts +++ b/arch/arm/dts/meson-gxbb-odroidc2.dts @@ -50,7 +50,7 @@ / { compatible = "hardkernel,odroid-c2", "amlogic,meson-gxbb"; model = "Hardkernel ODROID-C2"; - + aliases { serial0 = &uart_AO; }; @@ -135,6 +135,24 @@ compatible = "mmc-pwrseq-emmc"; reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; +}; + +&cec_AO { + status = "okay"; + pinctrl-0 = <&ao_cec_pins>; + pinctrl-names = "default"; + hdmi-phandle = <&hdmi_tx>; }; ðmac { @@ -156,7 +174,11 @@ #size-cells = <0>; eth_phy0: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ reg = <0>; + interrupt-parent = <&gpio_intc>; + /* MAC_INTR on GPIOZ_15 */ + interrupts = <29 IRQ_TYPE_LEVEL_LOW>; eee-broken-1000t; }; }; @@ -177,6 +199,18 @@ }; }; +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; + pinctrl-names = "default"; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; + &i2c_A { status = "okay"; pinctrl-0 = <&i2c_a_pins>; @@ -194,7 +228,9 @@ "USB HUB nRESET", "USB OTG Power En", "J7 Header Pin2", "IR In", "J7 Header Pin4", "J7 Header Pin6", "J7 Header Pin5", "J7 Header Pin7", - "HDMI CEC", "SYS LED"; + "HDMI CEC", "SYS LED", + /* GPIO_TEST_N */ + ""; }; &pinctrl_periphs { @@ -233,11 +269,9 @@ "J2 Header Pin12", "J2 Header Pin13", "J2 Header Pin8", "J2 Header Pin10", "", "", "", "", "", - "J2 Header Pin11", "", "J2 Header Pin7", + "J2 Header Pin11", "", "J2 Header Pin7", "", /* Bank GPIOCLK */ - "", "", "", "", - /* GPIO_TEST_N */ - ""; + "", "", "", ""; }; &saradc { @@ -253,7 +287,8 @@ &sd_emmc_b { status = "okay"; pinctrl-0 = <&sdcard_pins>; - pinctrl-names = "default"; + pinctrl-1 = <&sdcard_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; bus-width = <4>; cap-sd-highspeed; @@ -270,11 +305,11 @@ /* eMMC */ &sd_emmc_c { status = "okay"; - pinctrl-0 = <&emmc_pins>; - pinctrl-names = "default"; + pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; + pinctrl-1 = <&emmc_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; bus-width = <8>; - cap-sd-highspeed; max-frequency = <200000000>; non-removable; disable-wp; @@ -300,6 +335,7 @@ &usb1_phy { status = "okay"; + phy-supply = <&usb_otg_pwr>; }; &usb0 { diff --git a/arch/arm/dts/meson-gxbb.dtsi b/arch/arm/dts/meson-gxbb.dtsi index 17d3efdf14..3290a4dc35 100644 --- a/arch/arm/dts/meson-gxbb.dtsi +++ b/arch/arm/dts/meson-gxbb.dtsi @@ -307,6 +307,15 @@ }; }; +&cec_AO { + clocks = <&clkc_AO CLKID_AO_CEC_32K>; + clock-names = "core"; +}; + +&clkc_AO { + compatible = "amlogic,meson-gxbb-aoclkc", "amlogic,meson-gx-aoclkc"; +}; + ðmac { clocks = <&clkc CLKID_ETH>, <&clkc CLKID_FCLK_DIV2>, @@ -314,6 +323,12 @@ clock-names = "stmmaceth", "clkin0", "clkin1"; }; +&gpio_intc { + compatible = "amlogic,meson-gpio-intc", + "amlogic,meson-gxbb-gpio-intc"; + status = "okay"; +}; + &hdmi_tx { compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; resets = <&reset RESET_HDMITX_CAPB3>, @@ -370,19 +385,36 @@ reg-names = "mux", "pull", "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; - gpio-ranges = <&pinctrl_periphs 0 14 120>; + gpio-ranges = <&pinctrl_periphs 0 0 119>; }; emmc_pins: emmc { mux { groups = "emmc_nand_d07", "emmc_cmd", - "emmc_clk", - "emmc_ds"; + "emmc_clk"; + function = "emmc"; + }; + }; + + emmc_ds_pins: emmc-ds { + mux { + groups = "emmc_ds"; function = "emmc"; }; }; + emmc_clk_gate_pins: emmc_clk_gate { + mux { + groups = "BOOT_8"; + function = "gpio_periphs"; + }; + cfg-pull-down { + pins = "BOOT_8"; + bias-pull-down; + }; + }; + nor_pins: nor { mux { groups = "nor_d", @@ -421,6 +453,17 @@ }; }; + sdcard_clk_gate_pins: sdcard_clk_gate { + mux { + groups = "CARD_2"; + function = "gpio_periphs"; + }; + cfg-pull-down { + pins = "CARD_2"; + bias-pull-down; + }; + }; + sdio_pins: sdio { mux { groups = "sdio_d0", @@ -433,6 +476,17 @@ }; }; + sdio_clk_gate_pins: sdio_clk_gate { + mux { + groups = "GPIOX_4"; + function = "gpio_periphs"; + }; + cfg-pull-down { + pins = "GPIOX_4"; + bias-pull-down; + }; + }; + sdio_irq_pins: sdio_irq { mux { groups = "sdio_irq"; @@ -640,33 +694,74 @@ }; }; +&pwrc_vpu { + resets = <&reset RESET_VIU>, + <&reset RESET_VENC>, + <&reset RESET_VCBUS>, + <&reset RESET_BT656>, + <&reset RESET_DVIN_RESET>, + <&reset RESET_RDMA>, + <&reset RESET_VENCI>, + <&reset RESET_VENCP>, + <&reset RESET_VDAC>, + <&reset RESET_VDI6>, + <&reset RESET_VENCL>, + <&reset RESET_VID_LOCK>; + clocks = <&clkc CLKID_VPU>, + <&clkc CLKID_VAPB>; + clock-names = "vpu", "vapb"; + /* + * VPU clocking is provided by two identical clock paths + * VPU_0 and VPU_1 muxed to a single clock by a glitch + * free mux to safely change frequency while running. + * Same for VAPB but with a final gate after the glitch free mux. + */ + assigned-clocks = <&clkc CLKID_VPU_0_SEL>, + <&clkc CLKID_VPU_0>, + <&clkc CLKID_VPU>, /* Glitch free mux */ + <&clkc CLKID_VAPB_0_SEL>, + <&clkc CLKID_VAPB_0>, + <&clkc CLKID_VAPB_SEL>; /* Glitch free mux */ + assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, + <0>, /* Do Nothing */ + <&clkc CLKID_VPU_0>, + <&clkc CLKID_FCLK_DIV4>, + <0>, /* Do Nothing */ + <&clkc CLKID_VAPB_0>; + assigned-clock-rates = <0>, /* Do Nothing */ + <666666666>, + <0>, /* Do Nothing */ + <0>, /* Do Nothing */ + <250000000>, + <0>; /* Do Nothing */ +}; + &saradc { compatible = "amlogic,meson-gxbb-saradc", "amlogic,meson-saradc"; clocks = <&xtal>, <&clkc CLKID_SAR_ADC>, - <&clkc CLKID_SANA>, <&clkc CLKID_SAR_ADC_CLK>, <&clkc CLKID_SAR_ADC_SEL>; - clock-names = "clkin", "core", "sana", "adc_clk", "adc_sel"; + clock-names = "clkin", "core", "adc_clk", "adc_sel"; }; &sd_emmc_a { clocks = <&clkc CLKID_SD_EMMC_A>, - <&xtal>, + <&clkc CLKID_SD_EMMC_A_CLK0>, <&clkc CLKID_FCLK_DIV2>; clock-names = "core", "clkin0", "clkin1"; }; &sd_emmc_b { clocks = <&clkc CLKID_SD_EMMC_B>, - <&xtal>, + <&clkc CLKID_SD_EMMC_B_CLK0>, <&clkc CLKID_FCLK_DIV2>; clock-names = "core", "clkin0", "clkin1"; }; &sd_emmc_c { clocks = <&clkc CLKID_SD_EMMC_C>, - <&xtal>, + <&clkc CLKID_SD_EMMC_C_CLK0>, <&clkc CLKID_FCLK_DIV2>; clock-names = "core", "clkin0", "clkin1"; }; @@ -682,6 +777,32 @@ clocks = <&clkc CLKID_SPI>; }; +&uart_A { + clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + +&uart_AO { + clocks = <&xtal>, <&clkc CLKID_CLK81>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + +&uart_AO_B { + clocks = <&xtal>, <&clkc CLKID_CLK81>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + +&uart_B { + clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + +&uart_C { + clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + &vpu { compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu"; + power-domains = <&pwrc_vpu>; }; diff --git a/arch/arm/dts/meson-gxl-s905x-khadas-vim.dts b/arch/arm/dts/meson-gxl-s905x-khadas-vim.dts index 84cbebb534..c3515599ed 100644 --- a/arch/arm/dts/meson-gxl-s905x-khadas-vim.dts +++ b/arch/arm/dts/meson-gxl-s905x-khadas-vim.dts @@ -66,6 +66,13 @@ }; }; +&cec_AO { + status = "okay"; + pinctrl-0 = <&ao_cec_pins>; + pinctrl-names = "default"; + hdmi-phandle = <&hdmi_tx>; +}; + &hdmi_tx { status = "okay"; pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; @@ -104,6 +111,62 @@ linux,rc-map-name = "rc-geekbox"; }; +&pinctrl_aobus { + gpio-line-names = "UART TX", + "UART RX", + "Power Key In", + "J9 Header Pin35", + "J9 Header Pin16", + "J9 Header Pin15", + "J9 Header Pin33", + "IR In", + "HDMI CEC", + "SYS LED", + /* GPIO_TEST_N */ + ""; +}; + +&pinctrl_periphs { + gpio-line-names = /* Bank GPIOZ */ + "", "", "", "", "", "", "", + "", "", "", "", "", "", "", + "Power OFF", + "VCCK Enable", + /* Bank GPIOH */ + "HDMI HPD", "HDMI SDA", "HDMI SCL", + "HDMI_5V_EN", "SPDIF", + "J9 Header Pin37", + "J9 Header Pin30", + "J9 Header Pin29", + "J9 Header Pin32", + "J9 Header Pin31", + /* Bank BOOT */ + "eMMC D0", "eMMC D1", "eMMC D2", "eMMC D3", + "eMMC D4", "eMMC D5", "eMMC D6", "eMMC D7", + "eMMC Clk", "eMMC Reset", "eMMC CMD", + "", "BOOT_MODE", "", "", "eMMC Data Strobe", + /* Bank CARD */ + "SDCard D1", "SDCard D0", "SDCard CLK", "SDCard CMD", + "SDCard D3", "SDCard D2", "SDCard Det", + /* Bank GPIODV */ + "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", + "I2C A SDA", "I2C A SCK", "I2C B SDA", "I2C B SCK", + "VCCK Regulator", "VDDEE Regulator", + /* Bank GPIOX */ + "WIFI SDIO D0", "WIFI SDIO D1", "WIFI SDIO D2", + "WIFI SDIO D3", "WIFI SDIO CLK", "WIFI SDIO CMD", + "WIFI Power Enable", "WIFI WAKE HOST", + "Bluetooth PCM DOUT", "Bluetooth PCM DIN", + "Bluetooth PCM SYNC", "Bluetooth PCM CLK", + "Bluetooth UART TX", "Bluetooth UART RX", + "Bluetooth UART CTS", "Bluetooth UART RTS", + "WIFI 32K", "Bluetooth Enable", + "Bluetooth WAKE HOST", + /* Bank GPIOCLK */ + "", "J9 Header Pin39"; +}; + &pwm_AO_ab { status = "okay"; pinctrl-0 = <&pwm_ao_a_3_pins>, <&pwm_ao_b_pins>; diff --git a/arch/arm/dts/meson-gxl-s905x-libretech-cc.dts b/arch/arm/dts/meson-gxl-s905x-libretech-cc.dts index dc2acf4d16..9139761c79 100644 --- a/arch/arm/dts/meson-gxl-s905x-libretech-cc.dts +++ b/arch/arm/dts/meson-gxl-s905x-libretech-cc.dts @@ -71,6 +71,18 @@ reg = <0x0 0x0 0x0 0x80000000>; }; + hdmi_5v: regulator-hdmi-5v { + compatible = "regulator-fixed"; + + regulator-name = "HDMI_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + + gpio = <&gpio GPIOH_3 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + }; + vcc_3v3: regulator-vcc_3v3 { compatible = "regulator-fixed"; regulator-name = "VCC_3V3"; @@ -90,6 +102,16 @@ states = <3300000 0>, <1800000 1>; + + regulator-settling-time-up-us = <200>; + regulator-settling-time-down-us = <50000>; + }; + + vddio_ao18: regulator-vddio_ao18 { + compatible = "regulator-fixed"; + regulator-name = "VDDIO_AO18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; }; vddio_boot: regulator-vddio_boot { @@ -100,6 +122,13 @@ }; }; +&cec_AO { + status = "okay"; + pinctrl-0 = <&ao_cec_pins>; + pinctrl-names = "default"; + hdmi-phandle = <&hdmi_tx>; +}; + &cvbs_vdac_port { cvbs_vdac_out: endpoint { remote-endpoint = <&cvbs_connector_in>; @@ -110,6 +139,11 @@ status = "okay"; }; +&internal_phy { + pinctrl-0 = <ð_link_led_pins>, <ð_act_led_pins>; + pinctrl-names = "default"; +}; + &ir { status = "okay"; pinctrl-0 = <&remote_input_ao_pins>; @@ -128,14 +162,80 @@ }; }; +&pinctrl_aobus { + gpio-line-names = "UART TX", + "UART RX", + "Blue LED", + "SDCard Voltage Switch", + "7J1 Header Pin5", + "7J1 Header Pin3", + "7J1 Header Pin12", + "IR In", + "9J3 Switch HDMI CEC/7J1 Header Pin11", + "7J1 Header Pin13", + /* GPIO_TEST_N */ + "7J1 Header Pin15"; +}; + +&pinctrl_periphs { + gpio-line-names = /* Bank GPIOZ */ + "", "", "", "", "", "", "", + "", "", "", "", "", "", "", + "Eth Link LED", "Eth Activity LED", + /* Bank GPIOH */ + "HDMI HPD", "HDMI SDA", "HDMI SCL", + "HDMI_5V_EN", "9J1 Header Pin2", + "Analog Audio Mute", + "2J3 Header Pin6", + "2J3 Header Pin5", + "2J3 Header Pin4", + "2J3 Header Pin3", + /* Bank BOOT */ + "eMMC D0", "eMMC D1", "eMMC D2", "eMMC D3", + "eMMC D4", "eMMC D5", "eMMC D6", "eMMC D7", + "eMMC Clk", "eMMC Reset", "eMMC CMD", + "ALT BOOT MODE", "", "", "", "eMMC Data Strobe", + /* Bank CARD */ + "SDCard D1", "SDCard D0", "SDCard CLK", "SDCard CMD", + "SDCard D3", "SDCard D2", "SDCard Det", + /* Bank GPIODV */ + "", "", "", "", "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", "", "", "", "", + "Green LED", "VCCK Enable", + "7J1 Header Pin27", "7J1 Header Pin28", + "VCCK Regulator", "VDDEE Regulator", + /* Bank GPIOX */ + "7J1 Header Pin22", "7J1 Header Pin26", + "7J1 Header Pin36", "7J1 Header Pin38", + "7J1 Header Pin40", "7J1 Header Pin37", + "7J1 Header Pin33", "7J1 Header Pin35", + "7J1 Header Pin19", "7J1 Header Pin21", + "7J1 Header Pin24", "7J1 Header Pin23", + "7J1 Header Pin8", "7J1 Header Pin10", + "7J1 Header Pin16", "7J1 Header Pin18", + "7J1 Header Pin32", "7J1 Header Pin29", + "7J1 Header Pin31", + /* Bank GPIOCLK */ + "7J1 Header Pin7", ""; +}; + +&saradc { + status = "okay"; + vref-supply = <&vddio_ao18>; +}; + /* SD card */ &sd_emmc_b { status = "okay"; pinctrl-0 = <&sdcard_pins>; - pinctrl-names = "default"; + pinctrl-1 = <&sdcard_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; bus-width = <4>; cap-sd-highspeed; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; max-frequency = <100000000>; disable-wp; @@ -149,11 +249,13 @@ /* eMMC */ &sd_emmc_c { status = "okay"; - pinctrl-0 = <&emmc_pins>; - pinctrl-names = "default"; + pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; + pinctrl-1 = <&emmc_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; bus-width = <8>; cap-mmc-highspeed; + mmc-ddr-3_3v; max-frequency = <50000000>; non-removable; disable-wp; diff --git a/arch/arm/dts/meson-gxl-s905x-p212.dts b/arch/arm/dts/meson-gxl-s905x-p212.dts index 6ab17c1eee..6e2bf85829 100644 --- a/arch/arm/dts/meson-gxl-s905x-p212.dts +++ b/arch/arm/dts/meson-gxl-s905x-p212.dts @@ -71,6 +71,13 @@ }; }; +&cec_AO { + status = "okay"; + pinctrl-0 = <&ao_cec_pins>; + pinctrl-names = "default"; + hdmi-phandle = <&hdmi_tx>; +}; + &cvbs_vdac_port { cvbs_vdac_out: endpoint { remote-endpoint = <&cvbs_connector_in>; diff --git a/arch/arm/dts/meson-gxl-s905x-p212.dtsi b/arch/arm/dts/meson-gxl-s905x-p212.dtsi index 0385fb9861..2db1377819 100644 --- a/arch/arm/dts/meson-gxl-s905x-p212.dtsi +++ b/arch/arm/dts/meson-gxl-s905x-p212.dtsi @@ -27,6 +27,18 @@ reg = <0x0 0x0 0x0 0x80000000>; }; + hdmi_5v: regulator-hdmi-5v { + compatible = "regulator-fixed"; + + regulator-name = "HDMI_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + + gpio = <&gpio GPIOH_3 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-always-on; + }; + vddio_boot: regulator-vddio_boot { compatible = "regulator-fixed"; regulator-name = "VDDIO_BOOT"; @@ -94,7 +106,8 @@ &sd_emmc_a { status = "okay"; pinctrl-0 = <&sdio_pins>; - pinctrl-names = "default"; + pinctrl-1 = <&sdio_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; #address-cells = <1>; #size-cells = <0>; @@ -115,7 +128,8 @@ &sd_emmc_b { status = "okay"; pinctrl-0 = <&sdcard_pins>; - pinctrl-names = "default"; + pinctrl-1 = <&sdcard_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; bus-width = <4>; cap-sd-highspeed; @@ -132,11 +146,11 @@ /* eMMC */ &sd_emmc_c { status = "okay"; - pinctrl-0 = <&emmc_pins>; - pinctrl-names = "default"; + pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; + pinctrl-1 = <&emmc_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; bus-width = <8>; - cap-sd-highspeed; cap-mmc-highspeed; max-frequency = <200000000>; non-removable; diff --git a/arch/arm/dts/meson-gxl.dtsi b/arch/arm/dts/meson-gxl.dtsi index 8d4f3160a0..c8514110b9 100644 --- a/arch/arm/dts/meson-gxl.dtsi +++ b/arch/arm/dts/meson-gxl.dtsi @@ -43,11 +43,20 @@ #include "meson-gx.dtsi" #include <dt-bindings/clock/gxbb-clkc.h> +#include <dt-bindings/clock/gxbb-aoclkc.h> #include <dt-bindings/gpio/meson-gxl-gpio.h> #include <dt-bindings/reset/amlogic,meson-gxbb-reset.h> / { compatible = "amlogic,meson-gxl"; + + reserved-memory { + /* Alternate 3 MiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved_alt: secmon@5000000 { + reg = <0x0 0x05000000 0x0 0x300000>; + no-map; + }; + }; }; ðmac { @@ -207,6 +216,21 @@ }; }; +&cec_AO { + clocks = <&clkc_AO CLKID_AO_CEC_32K>; + clock-names = "core"; +}; + +&clkc_AO { + compatible = "amlogic,meson-gxl-aoclkc", "amlogic,meson-gx-aoclkc"; +}; + +&gpio_intc { + compatible = "amlogic,meson-gpio-intc", + "amlogic,meson-gxl-gpio-intc"; + status = "okay"; +}; + &hdmi_tx { compatible = "amlogic,meson-gxl-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; resets = <&reset RESET_HDMITX_CAPB3>, @@ -258,19 +282,36 @@ reg-names = "mux", "pull", "pull-enable", "gpio"; gpio-controller; #gpio-cells = <2>; - gpio-ranges = <&pinctrl_periphs 0 10 101>; + gpio-ranges = <&pinctrl_periphs 0 0 100>; }; emmc_pins: emmc { mux { groups = "emmc_nand_d07", "emmc_cmd", - "emmc_clk", - "emmc_ds"; + "emmc_clk"; function = "emmc"; }; }; + emmc_ds_pins: emmc-ds { + mux { + groups = "emmc_ds"; + function = "emmc"; + }; + }; + + emmc_clk_gate_pins: emmc_clk_gate { + mux { + groups = "BOOT_8"; + function = "gpio_periphs"; + }; + cfg-pull-down { + pins = "BOOT_8"; + bias-pull-down; + }; + }; + nor_pins: nor { mux { groups = "nor_d", @@ -309,6 +350,17 @@ }; }; + sdcard_clk_gate_pins: sdcard_clk_gate { + mux { + groups = "CARD_2"; + function = "gpio_periphs"; + }; + cfg-pull-down { + pins = "CARD_2"; + bias-pull-down; + }; + }; + sdio_pins: sdio { mux { groups = "sdio_d0", @@ -321,6 +373,17 @@ }; }; + sdio_clk_gate_pins: sdio_clk_gate { + mux { + groups = "GPIOX_4"; + function = "gpio_periphs"; + }; + cfg-pull-down { + pins = "GPIOX_4"; + bias-pull-down; + }; + }; + sdio_irq_pins: sdio_irq { mux { groups = "sdio_irq"; @@ -568,6 +631,7 @@ internal_phy: ethernet-phy@8 { compatible = "ethernet-phy-id0181.4400", "ethernet-phy-ieee802.3-c22"; + interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>; reg = <8>; max-speed = <100>; }; @@ -581,33 +645,74 @@ }; }; +&pwrc_vpu { + resets = <&reset RESET_VIU>, + <&reset RESET_VENC>, + <&reset RESET_VCBUS>, + <&reset RESET_BT656>, + <&reset RESET_DVIN_RESET>, + <&reset RESET_RDMA>, + <&reset RESET_VENCI>, + <&reset RESET_VENCP>, + <&reset RESET_VDAC>, + <&reset RESET_VDI6>, + <&reset RESET_VENCL>, + <&reset RESET_VID_LOCK>; + clocks = <&clkc CLKID_VPU>, + <&clkc CLKID_VAPB>; + clock-names = "vpu", "vapb"; + /* + * VPU clocking is provided by two identical clock paths + * VPU_0 and VPU_1 muxed to a single clock by a glitch + * free mux to safely change frequency while running. + * Same for VAPB but with a final gate after the glitch free mux. + */ + assigned-clocks = <&clkc CLKID_VPU_0_SEL>, + <&clkc CLKID_VPU_0>, + <&clkc CLKID_VPU>, /* Glitch free mux */ + <&clkc CLKID_VAPB_0_SEL>, + <&clkc CLKID_VAPB_0>, + <&clkc CLKID_VAPB_SEL>; /* Glitch free mux */ + assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, + <0>, /* Do Nothing */ + <&clkc CLKID_VPU_0>, + <&clkc CLKID_FCLK_DIV4>, + <0>, /* Do Nothing */ + <&clkc CLKID_VAPB_0>; + assigned-clock-rates = <0>, /* Do Nothing */ + <666666666>, + <0>, /* Do Nothing */ + <0>, /* Do Nothing */ + <250000000>, + <0>; /* Do Nothing */ +}; + &saradc { compatible = "amlogic,meson-gxl-saradc", "amlogic,meson-saradc"; clocks = <&xtal>, <&clkc CLKID_SAR_ADC>, - <&clkc CLKID_SANA>, <&clkc CLKID_SAR_ADC_CLK>, <&clkc CLKID_SAR_ADC_SEL>; - clock-names = "clkin", "core", "sana", "adc_clk", "adc_sel"; + clock-names = "clkin", "core", "adc_clk", "adc_sel"; }; &sd_emmc_a { clocks = <&clkc CLKID_SD_EMMC_A>, - <&xtal>, + <&clkc CLKID_SD_EMMC_A_CLK0>, <&clkc CLKID_FCLK_DIV2>; clock-names = "core", "clkin0", "clkin1"; }; &sd_emmc_b { clocks = <&clkc CLKID_SD_EMMC_B>, - <&xtal>, + <&clkc CLKID_SD_EMMC_B_CLK0>, <&clkc CLKID_FCLK_DIV2>; clock-names = "core", "clkin0", "clkin1"; }; &sd_emmc_c { clocks = <&clkc CLKID_SD_EMMC_C>, - <&xtal>, + <&clkc CLKID_SD_EMMC_C_CLK0>, <&clkc CLKID_FCLK_DIV2>; clock-names = "core", "clkin0", "clkin1"; }; @@ -623,6 +728,32 @@ clocks = <&clkc CLKID_SPI>; }; +&uart_A { + clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + +&uart_AO { + clocks = <&xtal>, <&clkc CLKID_CLK81>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + +&uart_AO_B { + clocks = <&xtal>, <&clkc CLKID_CLK81>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + +&uart_B { + clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + +&uart_C { + clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; + &vpu { compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu"; + power-domains = <&pwrc_vpu>; }; diff --git a/arch/arm/dts/stm32mp157.dtsi b/arch/arm/dts/stm32mp157.dtsi index b84899a1ea..2b894162e9 100644 --- a/arch/arm/dts/stm32mp157.dtsi +++ b/arch/arm/dts/stm32mp157.dtsi @@ -123,6 +123,48 @@ }; }; + pwr: pwr@50001000 { + compatible = "st,stm32mp1-pwr", "st,stm32-pwr", "syscon", "simple-mfd"; + reg = <0x50001000 0x400>; + system-power-controller; + interrupts = <GIC_SPI 149 IRQ_TYPE_NONE>; + st,sysrcc = <&rcc>; + clocks = <&rcc_clk PLL2_R>; + clock-names = "phyclk"; + + pwr-regulators@c { + compatible = "st,stm32mp1,pwr-reg"; + st,tzcr = <&rcc 0x0 0x1>; + + reg11: reg11 { + regulator-name = "reg11"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + }; + + reg18: reg18 { + regulator-name = "reg18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + usb33: usb33 { + regulator-name = "usb33"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; + + vrefbuf: vrefbuf@50025000 { + compatible = "st,stm32-vrefbuf"; + reg = <0x50025000 0x8>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2500000>; + clocks = <&rcc_clk VREF>; + status = "disabled"; + }; + pinctrl: pin-controller { compatible = "st,stm32mp157-pinctrl"; #address-cells = <1>; diff --git a/arch/arm/dts/stm32mp157c-ed1.dts b/arch/arm/dts/stm32mp157c-ed1.dts index 129cd02418..2334707422 100644 --- a/arch/arm/dts/stm32mp157c-ed1.dts +++ b/arch/arm/dts/stm32mp157c-ed1.dts @@ -10,6 +10,7 @@ #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/input/input.h> #include <dt-bindings/pinctrl/stm32-pinfunc.h> +#include <dt-bindings/mfd/st,stpmu1.h> / { model = "STMicroelectronics STM32MP157C pmic eval daughter"; @@ -23,6 +24,19 @@ memory { reg = <0xC0000000 0x40000000>; }; + + sd_switch: regulator-sd_switch { + compatible = "regulator-gpio"; + regulator-name = "sd_switch"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2900000>; + regulator-type = "voltage"; + regulator-always-on; + + gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>; + gpios-states = <0>; + states = <1800000 0x1 2900000 0x0>; + }; }; &gpioa { @@ -166,6 +180,262 @@ interrupt-controller; #interrupt-cells = <2>; status = "okay"; + + st,main_control_register = <0x04>; + st,vin_control_register = <0xc0>; + st,usb_control_register = <0x30>; + + regulators { + compatible = "st,stpmu1-regulators"; + + ldo1-supply = <&v3v3>; + ldo2-supply = <&v3v3>; + ldo3-supply = <&vdd_ddr>; + ldo5-supply = <&v3v3>; + ldo6-supply = <&v3v3>; + pwr_sw1-supply = <&bst_out>; + pwr_sw2-supply = <&bst_out>; + + vddcore: buck1 { + regulator-name = "vddcore"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <2>; + regulator-over-current-protection; + + regulator-state-standby { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1200000>; + regulator-mode = <8>; + }; + regulator-state-mem { + regulator-off-in-suspend; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + vdd_ddr: buck2 { + regulator-name = "vdd_ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <2>; + regulator-over-current-protection; + + regulator-state-standby { + regulator-suspend-microvolt = <1350000>; + regulator-on-in-suspend; + regulator-mode = <8>; + }; + regulator-state-mem { + regulator-suspend-microvolt = <1350000>; + regulator-on-in-suspend; + regulator-mode = <8>; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + vdd: buck3 { + regulator-name = "vdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + st,mask_reset; + regulator-initial-mode = <8>; + regulator-over-current-protection; + + regulator-state-standby { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + regulator-mode = <8>; + }; + regulator-state-mem { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + regulator-mode = <8>; + }; + regulator-state-disk { + regulator-suspend-microvolt = <3300000>; + regulator-on-in-suspend; + regulator-mode = <8>; + }; + }; + + v3v3: buck4 { + regulator-name = "v3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-over-current-protection; + regulator-initial-mode = <8>; + + regulator-state-standby { + regulator-suspend-microvolt = <3300000>; + regulator-unchanged-in-suspend; + regulator-mode = <8>; + }; + regulator-state-mem { + regulator-off-in-suspend; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + vdda: ldo1 { + regulator-name = "vdda"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + interrupts = <IT_CURLIM_LDO1 0>; + interrupt-parent = <&pmic>; + + regulator-state-standby { + regulator-suspend-microvolt = <2900000>; + regulator-unchanged-in-suspend; + }; + regulator-state-mem { + regulator-off-in-suspend; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + v2v8: ldo2 { + regulator-name = "v2v8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + interrupts = <IT_CURLIM_LDO2 0>; + interrupt-parent = <&pmic>; + + regulator-state-standby { + regulator-suspend-microvolt = <2800000>; + regulator-unchanged-in-suspend; + }; + regulator-state-mem { + regulator-off-in-suspend; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + vtt_ddr: ldo3 { + regulator-name = "vtt_ddr"; + regulator-min-microvolt = <0000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-over-current-protection; + + regulator-state-standby { + regulator-off-in-suspend; + }; + regulator-state-mem { + regulator-off-in-suspend; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + vdd_usb: ldo4 { + regulator-name = "vdd_usb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + interrupts = <IT_CURLIM_LDO4 0>; + interrupt-parent = <&pmic>; + + regulator-state-standby { + regulator-unchanged-in-suspend; + }; + regulator-state-mem { + regulator-off-in-suspend; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + vdd_sd: ldo5 { + regulator-name = "vdd_sd"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + interrupts = <IT_CURLIM_LDO5 0>; + interrupt-parent = <&pmic>; + regulator-boot-on; + + regulator-state-standby { + regulator-suspend-microvolt = <2900000>; + regulator-unchanged-in-suspend; + }; + regulator-state-mem { + regulator-off-in-suspend; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + v1v8: ldo6 { + regulator-name = "v1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + interrupts = <IT_CURLIM_LDO6 0>; + interrupt-parent = <&pmic>; + + regulator-state-standby { + regulator-suspend-microvolt = <1800000>; + regulator-unchanged-in-suspend; + }; + regulator-state-mem { + regulator-off-in-suspend; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + vref_ddr: vref_ddr { + regulator-name = "vref_ddr"; + regulator-always-on; + regulator-over-current-protection; + + regulator-state-standby { + regulator-on-in-suspend; + }; + regulator-state-mem { + regulator-on-in-suspend; + }; + regulator-state-disk { + regulator-off-in-suspend; + }; + }; + + bst_out: boost { + regulator-name = "bst_out"; + interrupts = <IT_OCP_BOOST 0>; + interrupt-parent = <&pmic>; + }; + + vbus_otg: pwr_sw1 { + regulator-name = "vbus_otg"; + interrupts = <IT_OCP_OTG 0>; + interrupt-parent = <&pmic>; + regulator-active-discharge; + }; + + vbus_sw: pwr_sw2 { + regulator-name = "vbus_sw"; + interrupts = <IT_OCP_SWOUT 0>; + interrupt-parent = <&pmic>; + regulator-active-discharge; + }; + }; }; }; @@ -177,6 +447,8 @@ st,negedge; st,pin-ckin; bus-width = <4>; + vmmc-supply = <&vdd_sd>; + vqmmc-supply = <&sd_switch>; sd-uhs-sdr12; sd-uhs-sdr25; sd-uhs-sdr50; diff --git a/arch/arm/include/asm/arch-meson/gx.h b/arch/arm/include/asm/arch-meson/gx.h new file mode 100644 index 0000000000..03fb6b03de --- /dev/null +++ b/arch/arm/include/asm/arch-meson/gx.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com> + */ + +#ifndef __GX_H__ +#define __GX_H__ + +#define GX_FIRMWARE_MEM_SIZE 0x1000000 + +#define GX_AOBUS_BASE 0xc8100000 +#define GX_PERIPHS_BASE 0xc8834400 +#define GX_HIU_BASE 0xc883c000 +#define GX_ETH_BASE 0xc9410000 + +/* Always-On Peripherals registers */ +#define GX_AO_ADDR(off) (GX_AOBUS_BASE + ((off) << 2)) + +#define GX_AO_SEC_GP_CFG0 GX_AO_ADDR(0x90) +#define GX_AO_SEC_GP_CFG3 GX_AO_ADDR(0x93) +#define GX_AO_SEC_GP_CFG4 GX_AO_ADDR(0x94) +#define GX_AO_SEC_GP_CFG5 GX_AO_ADDR(0x95) + +#define GX_AO_MEM_SIZE_MASK 0xFFFF0000 +#define GX_AO_MEM_SIZE_SHIFT 16 +#define GX_AO_BL31_RSVMEM_SIZE_MASK 0xFFFF0000 +#define GX_AO_BL31_RSVMEM_SIZE_SHIFT 16 +#define GX_AO_BL32_RSVMEM_SIZE_MASK 0xFFFF + +/* Peripherals registers */ +#define GX_PERIPHS_ADDR(off) (GX_PERIPHS_BASE + ((off) << 2)) + +/* GPIO registers 0 to 6 */ +#define _GX_GPIO_OFF(n) ((n) == 6 ? 0x08 : 0x0c + 3 * (n)) +#define GX_GPIO_EN(n) GX_PERIPHS_ADDR(_GX_GPIO_OFF(n) + 0) +#define GX_GPIO_IN(n) GX_PERIPHS_ADDR(_GX_GPIO_OFF(n) + 1) +#define GX_GPIO_OUT(n) GX_PERIPHS_ADDR(_GX_GPIO_OFF(n) + 2) + +#define GX_ETH_REG_0 GX_PERIPHS_ADDR(0x50) +#define GX_ETH_REG_1 GX_PERIPHS_ADDR(0x51) +#define GX_ETH_REG_2 GX_PERIPHS_ADDR(0x56) +#define GX_ETH_REG_3 GX_PERIPHS_ADDR(0x57) + +#define GX_ETH_REG_0_PHY_INTF BIT(0) +#define GX_ETH_REG_0_TX_PHASE(x) (((x) & 3) << 5) +#define GX_ETH_REG_0_TX_RATIO(x) (((x) & 7) << 7) +#define GX_ETH_REG_0_PHY_CLK_EN BIT(10) +#define GX_ETH_REG_0_INVERT_RMII_CLK BIT(11) +#define GX_ETH_REG_0_CLK_EN BIT(12) + +/* HIU registers */ +#define GX_HIU_ADDR(off) (GX_HIU_BASE + ((off) << 2)) + +#define GX_MEM_PD_REG_0 GX_HIU_ADDR(0x40) + +/* Ethernet memory power domain */ +#define GX_MEM_PD_REG_0_ETH_MASK (BIT(2) | BIT(3)) + +/* Clock gates */ +#define GX_GCLK_MPEG_0 GX_HIU_ADDR(0x50) +#define GX_GCLK_MPEG_1 GX_HIU_ADDR(0x51) +#define GX_GCLK_MPEG_2 GX_HIU_ADDR(0x52) +#define GX_GCLK_MPEG_OTHER GX_HIU_ADDR(0x53) +#define GX_GCLK_MPEG_AO GX_HIU_ADDR(0x54) + +#define GX_GCLK_MPEG_0_I2C BIT(9) +#define GX_GCLK_MPEG_1_ETH BIT(3) + +#endif /* __GX_H__ */ diff --git a/arch/arm/include/asm/arch-meson/gxbb.h b/arch/arm/include/asm/arch-meson/gxbb.h deleted file mode 100644 index c7713b27b9..0000000000 --- a/arch/arm/include/asm/arch-meson/gxbb.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com> - */ - -#ifndef __GXBB_H__ -#define __GXBB_H__ - -#define GXBB_FIRMWARE_MEM_SIZE 0x1000000 - -#define GXBB_AOBUS_BASE 0xc8100000 -#define GXBB_PERIPHS_BASE 0xc8834400 -#define GXBB_HIU_BASE 0xc883c000 -#define GXBB_ETH_BASE 0xc9410000 - -/* Always-On Peripherals registers */ -#define GXBB_AO_ADDR(off) (GXBB_AOBUS_BASE + ((off) << 2)) - -#define GXBB_AO_SEC_GP_CFG0 GXBB_AO_ADDR(0x90) -#define GXBB_AO_SEC_GP_CFG3 GXBB_AO_ADDR(0x93) -#define GXBB_AO_SEC_GP_CFG4 GXBB_AO_ADDR(0x94) -#define GXBB_AO_SEC_GP_CFG5 GXBB_AO_ADDR(0x95) - -#define GXBB_AO_MEM_SIZE_MASK 0xFFFF0000 -#define GXBB_AO_MEM_SIZE_SHIFT 16 -#define GXBB_AO_BL31_RSVMEM_SIZE_MASK 0xFFFF0000 -#define GXBB_AO_BL31_RSVMEM_SIZE_SHIFT 16 -#define GXBB_AO_BL32_RSVMEM_SIZE_MASK 0xFFFF - -/* Peripherals registers */ -#define GXBB_PERIPHS_ADDR(off) (GXBB_PERIPHS_BASE + ((off) << 2)) - -/* GPIO registers 0 to 6 */ -#define _GXBB_GPIO_OFF(n) ((n) == 6 ? 0x08 : 0x0c + 3 * (n)) -#define GXBB_GPIO_EN(n) GXBB_PERIPHS_ADDR(_GXBB_GPIO_OFF(n) + 0) -#define GXBB_GPIO_IN(n) GXBB_PERIPHS_ADDR(_GXBB_GPIO_OFF(n) + 1) -#define GXBB_GPIO_OUT(n) GXBB_PERIPHS_ADDR(_GXBB_GPIO_OFF(n) + 2) - -#define GXBB_ETH_REG_0 GXBB_PERIPHS_ADDR(0x50) -#define GXBB_ETH_REG_1 GXBB_PERIPHS_ADDR(0x51) -#define GXBB_ETH_REG_2 GXBB_PERIPHS_ADDR(0x56) -#define GXBB_ETH_REG_3 GXBB_PERIPHS_ADDR(0x57) - -#define GXBB_ETH_REG_0_PHY_INTF BIT(0) -#define GXBB_ETH_REG_0_TX_PHASE(x) (((x) & 3) << 5) -#define GXBB_ETH_REG_0_TX_RATIO(x) (((x) & 7) << 7) -#define GXBB_ETH_REG_0_PHY_CLK_EN BIT(10) -#define GXBB_ETH_REG_0_INVERT_RMII_CLK BIT(11) -#define GXBB_ETH_REG_0_CLK_EN BIT(12) - -/* HIU registers */ -#define GXBB_HIU_ADDR(off) (GXBB_HIU_BASE + ((off) << 2)) - -#define GXBB_MEM_PD_REG_0 GXBB_HIU_ADDR(0x40) - -/* Ethernet memory power domain */ -#define GXBB_MEM_PD_REG_0_ETH_MASK (BIT(2) | BIT(3)) - -/* Clock gates */ -#define GXBB_GCLK_MPEG_0 GXBB_HIU_ADDR(0x50) -#define GXBB_GCLK_MPEG_1 GXBB_HIU_ADDR(0x51) -#define GXBB_GCLK_MPEG_2 GXBB_HIU_ADDR(0x52) -#define GXBB_GCLK_MPEG_OTHER GXBB_HIU_ADDR(0x53) -#define GXBB_GCLK_MPEG_AO GXBB_HIU_ADDR(0x54) - -#define GXBB_GCLK_MPEG_0_I2C BIT(9) -#define GXBB_GCLK_MPEG_1_ETH BIT(3) - -#endif /* __GXBB_H__ */ diff --git a/arch/arm/mach-at91/include/mach/atmel_pio4.h b/arch/arm/mach-at91/include/mach/atmel_pio4.h index 81e0e9f332..7a03d6d3c7 100644 --- a/arch/arm/mach-at91/include/mach/atmel_pio4.h +++ b/arch/arm/mach-at91/include/mach/atmel_pio4.h @@ -47,6 +47,10 @@ struct atmel_pio4_port { #define ATMEL_PIO_IFSCEN_MASK BIT(13) #define ATMEL_PIO_OPD_MASK BIT(14) #define ATMEL_PIO_SCHMITT_MASK BIT(15) +#define ATMEL_PIO_DRVSTR_MASK GENMASK(17, 16) +#define ATMEL_PIO_DRVSTR_LO (1 << 16) +#define ATMEL_PIO_DRVSTR_ME (2 << 16) +#define ATMEL_PIO_DRVSTR_HI (3 << 16) #define ATMEL_PIO_CFGR_EVTSEL_MASK GENMASK(26, 24) #define ATMEL_PIO_CFGR_EVTSEL_FALLING (0 << 24) #define ATMEL_PIO_CFGR_EVTSEL_RISING (1 << 24) @@ -68,14 +72,14 @@ struct atmel_pio4_port { #define AT91_PIO_PORTC 0x2 #define AT91_PIO_PORTD 0x3 -int atmel_pio4_set_gpio(u32 port, u32 pin, u32 use_pullup); -int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 use_pullup); -int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 use_pullup); -int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 use_pullup); -int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 use_pullup); -int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 use_pullup); -int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 use_pullup); -int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 use_pullup); +int atmel_pio4_set_gpio(u32 port, u32 pin, u32 config); +int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 config); +int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 config); +int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 config); +int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 config); +int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 config); +int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 config); +int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 config); int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value); int atmel_pio4_get_pio_input(u32 port, u32 pin); diff --git a/arch/arm/mach-meson/board.c b/arch/arm/mach-meson/board.c index 89e75fb65b..1ef7e5a6d1 100644 --- a/arch/arm/mach-meson/board.c +++ b/arch/arm/mach-meson/board.c @@ -6,7 +6,7 @@ #include <common.h> #include <linux/libfdt.h> #include <linux/err.h> -#include <asm/arch/gxbb.h> +#include <asm/arch/gx.h> #include <asm/arch/sm.h> #include <asm/armv8/mmu.h> #include <asm/unaligned.h> @@ -39,8 +39,8 @@ int dram_init(void) phys_size_t get_effective_memsize(void) { /* Size is reported in MiB, convert it in bytes */ - return ((readl(GXBB_AO_SEC_GP_CFG0) & GXBB_AO_MEM_SIZE_MASK) - >> GXBB_AO_MEM_SIZE_SHIFT) * SZ_1M; + return ((readl(GX_AO_SEC_GP_CFG0) & GX_AO_MEM_SIZE_MASK) + >> GX_AO_MEM_SIZE_SHIFT) * SZ_1M; } static void meson_board_add_reserved_memory(void *fdt, u64 start, u64 size) @@ -71,27 +71,27 @@ void meson_gx_init_reserved_memory(void *fdt) * - AO_SEC_GP_CFG4: bl32 physical start address, can be NULL */ - reg = readl(GXBB_AO_SEC_GP_CFG3); + reg = readl(GX_AO_SEC_GP_CFG3); - bl31_size = ((reg & GXBB_AO_BL31_RSVMEM_SIZE_MASK) - >> GXBB_AO_BL31_RSVMEM_SIZE_SHIFT) * SZ_1K; - bl32_size = (reg & GXBB_AO_BL32_RSVMEM_SIZE_MASK) * SZ_1K; + bl31_size = ((reg & GX_AO_BL31_RSVMEM_SIZE_MASK) + >> GX_AO_BL31_RSVMEM_SIZE_SHIFT) * SZ_1K; + bl32_size = (reg & GX_AO_BL32_RSVMEM_SIZE_MASK) * SZ_1K; - bl31_start = readl(GXBB_AO_SEC_GP_CFG5); - bl32_start = readl(GXBB_AO_SEC_GP_CFG4); + bl31_start = readl(GX_AO_SEC_GP_CFG5); + bl32_start = readl(GX_AO_SEC_GP_CFG4); /* - * Early Meson GXBB Firmware revisions did not provide the reserved + * Early Meson GX Firmware revisions did not provide the reserved * memory zones in the registers, keep fixed memory zone handling. */ - if (IS_ENABLED(CONFIG_MESON_GXBB) && + if (IS_ENABLED(CONFIG_MESON_GX) && !reg && !bl31_start && !bl32_start) { bl31_start = 0x10000000; bl31_size = 0x200000; } /* Add first 16MiB reserved zone */ - meson_board_add_reserved_memory(fdt, 0, GXBB_FIRMWARE_MEM_SIZE); + meson_board_add_reserved_memory(fdt, 0, GX_FIRMWARE_MEM_SIZE); /* Add BL31 reserved zone */ if (bl31_start && bl31_size) @@ -107,7 +107,7 @@ void reset_cpu(ulong addr) psci_system_reset(); } -static struct mm_region gxbb_mem_map[] = { +static struct mm_region gx_mem_map[] = { { .virt = 0x0UL, .phys = 0x0UL, @@ -127,4 +127,4 @@ static struct mm_region gxbb_mem_map[] = { } }; -struct mm_region *mem_map = gxbb_mem_map; +struct mm_region *mem_map = gx_mem_map; diff --git a/arch/arm/mach-meson/eth.c b/arch/arm/mach-meson/eth.c index e340212c2a..061f19a0e3 100644 --- a/arch/arm/mach-meson/eth.c +++ b/arch/arm/mach-meson/eth.c @@ -7,7 +7,7 @@ #include <common.h> #include <dm.h> #include <asm/io.h> -#include <asm/arch/gxbb.h> +#include <asm/arch/gx.h> #include <asm/arch/eth.h> #include <phy.h> @@ -22,23 +22,23 @@ void meson_gx_eth_init(phy_interface_t mode, unsigned int flags) case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: /* Set RGMII mode */ - setbits_le32(GXBB_ETH_REG_0, GXBB_ETH_REG_0_PHY_INTF | - GXBB_ETH_REG_0_TX_PHASE(1) | - GXBB_ETH_REG_0_TX_RATIO(4) | - GXBB_ETH_REG_0_PHY_CLK_EN | - GXBB_ETH_REG_0_CLK_EN); + setbits_le32(GX_ETH_REG_0, GX_ETH_REG_0_PHY_INTF | + GX_ETH_REG_0_TX_PHASE(1) | + GX_ETH_REG_0_TX_RATIO(4) | + GX_ETH_REG_0_PHY_CLK_EN | + GX_ETH_REG_0_CLK_EN); break; case PHY_INTERFACE_MODE_RMII: /* Set RMII mode */ - out_le32(GXBB_ETH_REG_0, GXBB_ETH_REG_0_INVERT_RMII_CLK | - GXBB_ETH_REG_0_CLK_EN); + out_le32(GX_ETH_REG_0, GX_ETH_REG_0_INVERT_RMII_CLK | + GX_ETH_REG_0_CLK_EN); /* Use GXL RMII Internal PHY */ if (IS_ENABLED(CONFIG_MESON_GXL) && (flags & MESON_GXL_USE_INTERNAL_RMII_PHY)) { - writel(0x10110181, GXBB_ETH_REG_2); - writel(0xe40908ff, GXBB_ETH_REG_3); + writel(0x10110181, GX_ETH_REG_2); + writel(0xe40908ff, GX_ETH_REG_3); } break; @@ -49,6 +49,6 @@ void meson_gx_eth_init(phy_interface_t mode, unsigned int flags) } /* Enable power and clock gate */ - setbits_le32(GXBB_GCLK_MPEG_1, GXBB_GCLK_MPEG_1_ETH); - clrbits_le32(GXBB_MEM_PD_REG_0, GXBB_MEM_PD_REG_0_ETH_MASK); + setbits_le32(GX_GCLK_MPEG_1, GX_GCLK_MPEG_1_ETH); + clrbits_le32(GX_MEM_PD_REG_0, GX_MEM_PD_REG_0_ETH_MASK); } diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index 9829bae657..0bba5e4a07 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -6,7 +6,7 @@ */ #include <common.h> -#include <asm/arch/gxbb.h> +#include <asm/arch/gx.h> #include <linux/kernel.h> #define FN_GET_SHARE_MEM_INPUT_BASE 0x82000020 diff --git a/arch/arm/mach-omap2/utils.c b/arch/arm/mach-omap2/utils.c index 92a6f799d4..dc7b37f164 100644 --- a/arch/arm/mach-omap2/utils.c +++ b/arch/arm/mach-omap2/utils.c @@ -29,6 +29,8 @@ static void omap_set_fastboot_cpu(void) switch (cpu_rev) { case DRA762_ES1_0: + case DRA762_ABZ_ES1_0: + case DRA762_ACD_ES1_0: cpu = "DRA762"; break; case DRA752_ES1_0: diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile index a9b523d96f..08ee642d90 100644 --- a/arch/arm/mach-stm32mp/Makefile +++ b/arch/arm/mach-stm32mp/Makefile @@ -9,3 +9,4 @@ obj-y += syscon.o obj-$(CONFIG_SPL_BUILD) += spl.o obj-$(CONFIG_ARMV7_PSCI) += psci.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR) += pwr_regulator.o diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index afcab299cf..a8142013b0 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -28,6 +28,7 @@ enum { STM32MP_SYSCON_UNKNOWN, STM32MP_SYSCON_STGEN, + STM32MP_SYSCON_PWR, }; /* diff --git a/arch/arm/mach-stm32mp/pwr_regulator.c b/arch/arm/mach-stm32mp/pwr_regulator.c new file mode 100644 index 0000000000..9484645dbd --- /dev/null +++ b/arch/arm/mach-stm32mp/pwr_regulator.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <regmap.h> +#include <syscon.h> +#include <power/pmic.h> +#include <power/regulator.h> + +#define STM32MP_PWR_CR3 0xc +#define STM32MP_PWR_CR3_USB33DEN BIT(24) +#define STM32MP_PWR_CR3_USB33RDY BIT(26) +#define STM32MP_PWR_CR3_REG18DEN BIT(28) +#define STM32MP_PWR_CR3_REG18RDY BIT(29) +#define STM32MP_PWR_CR3_REG11DEN BIT(30) +#define STM32MP_PWR_CR3_REG11RDY BIT(31) + +struct stm32mp_pwr_reg_info { + u32 enable; + u32 ready; + char *name; +}; + +struct stm32mp_pwr_priv { + struct regmap *regmap; +}; + +static int stm32mp_pwr_write(struct udevice *dev, uint reg, + const uint8_t *buff, int len) +{ + struct stm32mp_pwr_priv *priv = dev_get_priv(dev); + u32 val = *(u32 *)buff; + + if (len != 4) + return -EINVAL; + + return regmap_write(priv->regmap, STM32MP_PWR_CR3, val); +} + +static int stm32mp_pwr_read(struct udevice *dev, uint reg, uint8_t *buff, + int len) +{ + struct stm32mp_pwr_priv *priv = dev_get_priv(dev); + + if (len != 4) + return -EINVAL; + + return regmap_read(priv->regmap, STM32MP_PWR_CR3, (u32 *)buff); +} + +static int stm32mp_pwr_ofdata_to_platdata(struct udevice *dev) +{ + struct stm32mp_pwr_priv *priv = dev_get_priv(dev); + struct regmap *regmap; + + regmap = syscon_get_regmap_by_driver_data(STM32MP_SYSCON_PWR); + if (IS_ERR(regmap)) { + pr_err("%s: unable to find regmap (%ld)\n", __func__, + PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + priv->regmap = regmap; + + return 0; +} + +static const struct pmic_child_info pwr_children_info[] = { + { .prefix = "reg", .driver = "stm32mp_pwr_regulator"}, + { .prefix = "usb", .driver = "stm32mp_pwr_regulator"}, + { }, +}; + +static int stm32mp_pwr_bind(struct udevice *dev) +{ + int children; + + children = pmic_bind_children(dev, dev->node, pwr_children_info); + if (!children) + dev_dbg(dev, "no child found\n"); + + return 0; +} + +static struct dm_pmic_ops stm32mp_pwr_ops = { + .read = stm32mp_pwr_read, + .write = stm32mp_pwr_write, +}; + +static const struct udevice_id stm32mp_pwr_ids[] = { + { .compatible = "st,stm32mp1,pwr-reg" }, + { } +}; + +U_BOOT_DRIVER(stm32mp_pwr_pmic) = { + .name = "stm32mp_pwr_pmic", + .id = UCLASS_PMIC, + .of_match = stm32mp_pwr_ids, + .bind = stm32mp_pwr_bind, + .ops = &stm32mp_pwr_ops, + .ofdata_to_platdata = stm32mp_pwr_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct stm32mp_pwr_priv), +}; + +static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg11 = { + .enable = STM32MP_PWR_CR3_REG11DEN, + .ready = STM32MP_PWR_CR3_REG11RDY, + .name = "reg11" +}; + +static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg18 = { + .enable = STM32MP_PWR_CR3_REG18DEN, + .ready = STM32MP_PWR_CR3_REG18RDY, + .name = "reg18" +}; + +static const struct stm32mp_pwr_reg_info stm32mp_pwr_usb33 = { + .enable = STM32MP_PWR_CR3_USB33DEN, + .ready = STM32MP_PWR_CR3_USB33RDY, + .name = "usb33" +}; + +static const struct stm32mp_pwr_reg_info *stm32mp_pwr_reg_infos[] = { + &stm32mp_pwr_reg11, + &stm32mp_pwr_reg18, + &stm32mp_pwr_usb33, + NULL +}; + +static int stm32mp_pwr_regulator_probe(struct udevice *dev) +{ + const struct stm32mp_pwr_reg_info **p = stm32mp_pwr_reg_infos; + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + while (*p) { + int rc; + + rc = dev_read_stringlist_search(dev, "regulator-name", + (*p)->name); + if (rc >= 0) { + dev_dbg(dev, "found regulator %s\n", (*p)->name); + break; + } else if (rc != -ENODATA) { + return rc; + } + p++; + } + if (!*p) { + int i = 0; + const char *s; + + dev_dbg(dev, "regulator "); + while (dev_read_string_index(dev, "regulator-name", + i++, &s) >= 0) + dev_dbg(dev, "%s'%s' ", (i > 1) ? ", " : "", s); + dev_dbg(dev, "%s not supported\n", (i > 2) ? "are" : "is"); + return -EINVAL; + } + + uc_pdata->type = REGULATOR_TYPE_FIXED; + dev->priv = (void *)*p; + + return 0; +} + +static int stm32mp_pwr_regulator_set_value(struct udevice *dev, int uV) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + if (!uc_pdata) + return -ENXIO; + + if (uc_pdata->min_uV != uV) { + dev_dbg(dev, "Invalid uV=%d for: %s\n", uV, uc_pdata->name); + return -EINVAL; + } + + return 0; +} + +static int stm32mp_pwr_regulator_get_value(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + if (!uc_pdata) + return -ENXIO; + + if (uc_pdata->min_uV != uc_pdata->max_uV) { + dev_dbg(dev, "Invalid constraints for: %s\n", uc_pdata->name); + return -EINVAL; + } + + return uc_pdata->min_uV; +} + +static int stm32mp_pwr_regulator_get_enable(struct udevice *dev) +{ + const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev); + int rc; + u32 reg; + + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); + if (rc) + return rc; + + dev_dbg(dev, "%s id %s\n", p->name, (reg & p->enable) ? "on" : "off"); + + return (reg & p->enable) != 0; +} + +static int stm32mp_pwr_regulator_set_enable(struct udevice *dev, bool enable) +{ + const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev); + int rc; + u32 reg; + u32 time_start; + + dev_dbg(dev, "Turning %s %s\n", enable ? "on" : "off", p->name); + + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); + if (rc) + return rc; + + /* if regulator is already in the wanted state, nothing to do */ + if (!!(reg & p->enable) == enable) + return 0; + + reg &= ~p->enable; + if (enable) + reg |= p->enable; + + rc = pmic_write(dev->parent, 0, (uint8_t *)®, sizeof(reg)); + if (rc) + return rc; + + if (!enable) + return 0; + + /* waiting ready for enable */ + time_start = get_timer(0); + while (1) { + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); + if (rc) + return rc; + if (reg & p->ready) + break; + if (get_timer(time_start) > CONFIG_SYS_HZ) { + dev_dbg(dev, "%s: timeout\n", p->name); + return -ETIMEDOUT; + } + } + return 0; +} + +static const struct dm_regulator_ops stm32mp_pwr_regulator_ops = { + .set_value = stm32mp_pwr_regulator_set_value, + .get_value = stm32mp_pwr_regulator_get_value, + .get_enable = stm32mp_pwr_regulator_get_enable, + .set_enable = stm32mp_pwr_regulator_set_enable, +}; + +U_BOOT_DRIVER(stm32mp_pwr_regulator) = { + .name = "stm32mp_pwr_regulator", + .id = UCLASS_REGULATOR, + .ops = &stm32mp_pwr_regulator_ops, + .probe = stm32mp_pwr_regulator_probe, +}; diff --git a/arch/arm/mach-stm32mp/syscon.c b/arch/arm/mach-stm32mp/syscon.c index 66b94f592f..eb7f435f10 100644 --- a/arch/arm/mach-stm32mp/syscon.c +++ b/arch/arm/mach-stm32mp/syscon.c @@ -11,6 +11,8 @@ static const struct udevice_id stm32mp_syscon_ids[] = { { .compatible = "st,stm32-stgen", .data = STM32MP_SYSCON_STGEN }, + { .compatible = "st,stm32mp1-pwr", + .data = STM32MP_SYSCON_PWR }, { } }; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 3c25cb79ef..683b1970e0 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -254,6 +254,18 @@ gpios = <&gpio_a 2 0>; label = "sandbox:green"; }; + + default_on { + gpios = <&gpio_a 5 0>; + label = "sandbox:default_on"; + default-state = "on"; + }; + + default_off { + gpios = <&gpio_a 6 0>; + label = "sandbox:default_off"; + default-state = "off"; + }; }; mbox: mbox { diff --git a/board/amlogic/khadas-vim/khadas-vim.c b/board/amlogic/khadas-vim/khadas-vim.c index d3ae7aa655..692bf2add3 100644 --- a/board/amlogic/khadas-vim/khadas-vim.c +++ b/board/amlogic/khadas-vim/khadas-vim.c @@ -8,7 +8,7 @@ #include <dm.h> #include <environment.h> #include <asm/io.h> -#include <asm/arch/gxbb.h> +#include <asm/arch/gx.h> #include <asm/arch/mem.h> #include <asm/arch/sm.h> #include <asm/arch/eth.h> diff --git a/board/amlogic/libretech-cc/libretech-cc.c b/board/amlogic/libretech-cc/libretech-cc.c index 80c04fb9cd..e89bf773cc 100644 --- a/board/amlogic/libretech-cc/libretech-cc.c +++ b/board/amlogic/libretech-cc/libretech-cc.c @@ -8,7 +8,7 @@ #include <dm.h> #include <environment.h> #include <asm/io.h> -#include <asm/arch/gxbb.h> +#include <asm/arch/gx.h> #include <asm/arch/sm.h> #include <asm/arch/eth.h> #include <asm/arch/mem.h> @@ -33,8 +33,8 @@ int misc_init_r(void) MESON_GXL_USE_INTERNAL_RMII_PHY); /* Enable power and clock gate */ - setbits_le32(GXBB_GCLK_MPEG_1, GXBB_GCLK_MPEG_1_ETH); - clrbits_le32(GXBB_MEM_PD_REG_0, GXBB_MEM_PD_REG_0_ETH_MASK); + setbits_le32(GX_GCLK_MPEG_1, GX_GCLK_MPEG_1_ETH); + clrbits_le32(GX_MEM_PD_REG_0, GX_MEM_PD_REG_0_ETH_MASK); if (!eth_env_get_enetaddr("ethaddr", mac_addr)) { len = meson_sm_read_efuse(EFUSE_MAC_OFFSET, diff --git a/board/amlogic/odroid-c2/odroid-c2.c b/board/amlogic/odroid-c2/odroid-c2.c index 339a1bf9ca..1b7fd8199b 100644 --- a/board/amlogic/odroid-c2/odroid-c2.c +++ b/board/amlogic/odroid-c2/odroid-c2.c @@ -7,7 +7,7 @@ #include <dm.h> #include <environment.h> #include <asm/io.h> -#include <asm/arch/gxbb.h> +#include <asm/arch/gx.h> #include <asm/arch/sm.h> #include <asm/arch/eth.h> #include <asm/arch/mem.h> @@ -31,13 +31,13 @@ int misc_init_r(void) meson_gx_eth_init(PHY_INTERFACE_MODE_RGMII, 0); /* Enable power and clock gate */ - setbits_le32(GXBB_GCLK_MPEG_0, GXBB_GCLK_MPEG_0_I2C); + setbits_le32(GX_GCLK_MPEG_0, GX_GCLK_MPEG_0_I2C); /* Reset PHY on GPIOZ_14 */ - clrbits_le32(GXBB_GPIO_EN(3), BIT(14)); - clrbits_le32(GXBB_GPIO_OUT(3), BIT(14)); + clrbits_le32(GX_GPIO_EN(3), BIT(14)); + clrbits_le32(GX_GPIO_OUT(3), BIT(14)); mdelay(10); - setbits_le32(GXBB_GPIO_OUT(3), BIT(14)); + setbits_le32(GX_GPIO_OUT(3), BIT(14)); if (!eth_env_get_enetaddr("ethaddr", mac_addr)) { len = meson_sm_read_efuse(EFUSE_MAC_OFFSET, diff --git a/board/amlogic/p212/p212.c b/board/amlogic/p212/p212.c index c1f2aca567..06c2eaee47 100644 --- a/board/amlogic/p212/p212.c +++ b/board/amlogic/p212/p212.c @@ -8,7 +8,7 @@ #include <dm.h> #include <environment.h> #include <asm/io.h> -#include <asm/arch/gxbb.h> +#include <asm/arch/gx.h> #include <asm/arch/sm.h> #include <asm/arch/eth.h> #include <asm/arch/mem.h> diff --git a/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c b/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c index d805068ac9..d5ddf8d2eb 100644 --- a/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c +++ b/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c @@ -19,7 +19,7 @@ DECLARE_GLOBAL_DATA_PTR; static void board_usb_hw_init(void) { - atmel_pio4_set_pio_output(AT91_PIO_PORTB, 10, 1); + atmel_pio4_set_pio_output(AT91_PIO_PORTA, 27, 1); } #ifdef CONFIG_BOARD_LATE_INIT @@ -35,7 +35,7 @@ int board_late_init(void) #ifdef CONFIG_DEBUG_UART_BOARD_INIT static void board_uart1_hw_init(void) { - atmel_pio4_set_a_periph(AT91_PIO_PORTD, 2, 1); /* URXD1 */ + atmel_pio4_set_a_periph(AT91_PIO_PORTD, 2, ATMEL_PIO_PUEN_MASK); /* URXD1 */ atmel_pio4_set_a_periph(AT91_PIO_PORTD, 3, 0); /* UTXD1 */ at91_periph_clk_enable(ATMEL_ID_UART1); diff --git a/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c b/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c index ff6efbf383..789841e45a 100644 --- a/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c +++ b/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c @@ -33,10 +33,10 @@ static void board_nand_hw_init(void) writel(AT91_SMC_SETUP_NWE(1) | AT91_SMC_SETUP_NCS_WR(1) | AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(1), &smc->cs[3].setup); - writel(AT91_SMC_PULSE_NWE(2) | AT91_SMC_PULSE_NCS_WR(3) | + writel(AT91_SMC_PULSE_NWE(2) | AT91_SMC_PULSE_NCS_WR(4) | AT91_SMC_PULSE_NRD(2) | AT91_SMC_PULSE_NCS_RD(3), &smc->cs[3].pulse); - writel(AT91_SMC_CYCLE_NWE(5) | AT91_SMC_CYCLE_NRD(5), + writel(AT91_SMC_CYCLE_NWE(6) | AT91_SMC_CYCLE_NRD(5), &smc->cs[3].cycle); writel(AT91_SMC_TIMINGS_TCLR(2) | AT91_SMC_TIMINGS_TADL(7) | AT91_SMC_TIMINGS_TAR(2) | AT91_SMC_TIMINGS_TRR(3) | @@ -48,32 +48,32 @@ static void board_nand_hw_init(void) AT91_SMC_MODE_TDF_CYCLE(3), &smc->cs[3].mode); - atmel_pio4_set_b_periph(AT91_PIO_PORTA, 22, 0); /* D0 */ - atmel_pio4_set_b_periph(AT91_PIO_PORTA, 23, 0); /* D1 */ - atmel_pio4_set_b_periph(AT91_PIO_PORTA, 24, 0); /* D2 */ - atmel_pio4_set_b_periph(AT91_PIO_PORTA, 25, 0); /* D3 */ - atmel_pio4_set_b_periph(AT91_PIO_PORTA, 26, 0); /* D4 */ - atmel_pio4_set_b_periph(AT91_PIO_PORTA, 27, 0); /* D5 */ - atmel_pio4_set_b_periph(AT91_PIO_PORTA, 28, 0); /* D6 */ - atmel_pio4_set_b_periph(AT91_PIO_PORTA, 29, 0); /* D7 */ + atmel_pio4_set_b_periph(AT91_PIO_PORTA, 22, ATMEL_PIO_DRVSTR_ME); /* D0 */ + atmel_pio4_set_b_periph(AT91_PIO_PORTA, 23, ATMEL_PIO_DRVSTR_ME); /* D1 */ + atmel_pio4_set_b_periph(AT91_PIO_PORTA, 24, ATMEL_PIO_DRVSTR_ME); /* D2 */ + atmel_pio4_set_b_periph(AT91_PIO_PORTA, 25, ATMEL_PIO_DRVSTR_ME); /* D3 */ + atmel_pio4_set_b_periph(AT91_PIO_PORTA, 26, ATMEL_PIO_DRVSTR_ME); /* D4 */ + atmel_pio4_set_b_periph(AT91_PIO_PORTA, 27, ATMEL_PIO_DRVSTR_ME); /* D5 */ + atmel_pio4_set_b_periph(AT91_PIO_PORTA, 28, ATMEL_PIO_DRVSTR_ME); /* D6 */ + atmel_pio4_set_b_periph(AT91_PIO_PORTA, 29, ATMEL_PIO_DRVSTR_ME); /* D7 */ atmel_pio4_set_b_periph(AT91_PIO_PORTB, 2, 0); /* RE */ atmel_pio4_set_b_periph(AT91_PIO_PORTA, 30, 0); /* WE */ - atmel_pio4_set_b_periph(AT91_PIO_PORTA, 31, 1); /* NCS */ - atmel_pio4_set_b_periph(AT91_PIO_PORTC, 8, 1); /* RDY */ - atmel_pio4_set_b_periph(AT91_PIO_PORTB, 0, 1); /* ALE */ - atmel_pio4_set_b_periph(AT91_PIO_PORTB, 1, 1); /* CLE */ + atmel_pio4_set_b_periph(AT91_PIO_PORTA, 31, ATMEL_PIO_PUEN_MASK); /* NCS */ + atmel_pio4_set_b_periph(AT91_PIO_PORTC, 8, ATMEL_PIO_PUEN_MASK); /* RDY */ + atmel_pio4_set_b_periph(AT91_PIO_PORTB, 0, ATMEL_PIO_PUEN_MASK); /* ALE */ + atmel_pio4_set_b_periph(AT91_PIO_PORTB, 1, ATMEL_PIO_PUEN_MASK); /* CLE */ } #endif static void board_usb_hw_init(void) { - atmel_pio4_set_pio_output(AT91_PIO_PORTB, 12, 1); + atmel_pio4_set_pio_output(AT91_PIO_PORTB, 12, ATMEL_PIO_PUEN_MASK); } #ifdef CONFIG_DEBUG_UART_BOARD_INIT static void board_uart0_hw_init(void) { - atmel_pio4_set_c_periph(AT91_PIO_PORTB, 26, 1); /* URXD0 */ + atmel_pio4_set_c_periph(AT91_PIO_PORTB, 26, ATMEL_PIO_PUEN_MASK); /* URXD0 */ atmel_pio4_set_c_periph(AT91_PIO_PORTB, 27, 0); /* UTXD0 */ at91_periph_clk_enable(ATMEL_ID_UART0); diff --git a/board/atmel/sama5d2_xplained/sama5d2_xplained.c b/board/atmel/sama5d2_xplained/sama5d2_xplained.c index 0ae2e2fec6..592b4d82dd 100644 --- a/board/atmel/sama5d2_xplained/sama5d2_xplained.c +++ b/board/atmel/sama5d2_xplained/sama5d2_xplained.c @@ -35,7 +35,7 @@ int board_late_init(void) #ifdef CONFIG_DEBUG_UART_BOARD_INIT static void board_uart1_hw_init(void) { - atmel_pio4_set_a_periph(AT91_PIO_PORTD, 2, 1); /* URXD1 */ + atmel_pio4_set_a_periph(AT91_PIO_PORTD, 2, ATMEL_PIO_PUEN_MASK); /* URXD1 */ atmel_pio4_set_a_periph(AT91_PIO_PORTD, 3, 0); /* UTXD1 */ at91_periph_clk_enable(ATMEL_ID_UART1); diff --git a/cmd/Kconfig b/cmd/Kconfig index 43240317ca..ae49b82471 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1445,6 +1445,20 @@ config CMD_HASH saved to memory or to an environment variable. It is also possible to verify a hash against data in memory. +config CMD_HVC + bool "Support the 'hvc' command" + depends on ARM_SMCCC + help + Allows issuing Hypervisor Calls (HVCs). Mostly useful for + development and testing. + +config CMD_SMC + bool "Support the 'smc' command" + depends on ARM_SMCCC + help + Allows issuing Secure Monitor Calls (SMCs). Mostly useful for + development and testing. + config HASH_VERIFY bool "hash -v" depends on CMD_HASH diff --git a/cmd/Makefile b/cmd/Makefile index 9695309cc2..d7349023a4 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_CMD_FS_GENERIC) += fs.o obj-$(CONFIG_CMD_FUSE) += fuse.o obj-$(CONFIG_CMD_GETTIME) += gettime.o obj-$(CONFIG_CMD_GPIO) += gpio.o +obj-$(CONFIG_CMD_HVC) += smccc.o obj-$(CONFIG_CMD_I2C) += i2c.o obj-$(CONFIG_CMD_IOTRACE) += iotrace.o obj-$(CONFIG_CMD_HASH) += hash.o @@ -112,6 +113,7 @@ obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o obj-$(CONFIG_CMD_SETEXPR) += setexpr.o obj-$(CONFIG_CMD_SPI) += spi.o obj-$(CONFIG_CMD_STRINGS) += strings.o +obj-$(CONFIG_CMD_SMC) += smccc.o obj-$(CONFIG_CMD_TERMINAL) += terminal.o obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_TRACE) += trace.o @@ -8,6 +8,8 @@ #include <command.h> #include <console.h> #include <mmc.h> +#include <sparse_format.h> +#include <image-sparse.h> static int curr_device = -1; @@ -307,6 +309,71 @@ static int do_mmc_read(cmd_tbl_t *cmdtp, int flag, } #if CONFIG_IS_ENABLED(MMC_WRITE) +#if defined(CONFIG_FASTBOOT_FLASH) +static lbaint_t mmc_sparse_write(struct sparse_storage *info, lbaint_t blk, + lbaint_t blkcnt, const void *buffer) +{ + struct blk_desc *dev_desc = info->priv; + + return blk_dwrite(dev_desc, blk, blkcnt, buffer); +} + +static lbaint_t mmc_sparse_reserve(struct sparse_storage *info, + lbaint_t blk, lbaint_t blkcnt) +{ + return blkcnt; +} + +static int do_mmc_sparse_write(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + struct sparse_storage sparse; + struct blk_desc *dev_desc; + struct mmc *mmc; + char dest[11]; + void *addr; + u32 blk; + + if (argc != 3) + return CMD_RET_USAGE; + + addr = (void *)simple_strtoul(argv[1], NULL, 16); + blk = simple_strtoul(argv[2], NULL, 16); + + if (!is_sparse_image(addr)) { + printf("Not a sparse image\n"); + return CMD_RET_FAILURE; + } + + mmc = init_mmc_device(curr_device, false); + if (!mmc) + return CMD_RET_FAILURE; + + printf("\nMMC Sparse write: dev # %d, block # %d ... ", + curr_device, blk); + + if (mmc_getwp(mmc) == 1) { + printf("Error: card is write protected!\n"); + return CMD_RET_FAILURE; + } + + dev_desc = mmc_get_blk_desc(mmc); + sparse.priv = dev_desc; + sparse.blksz = 512; + sparse.start = blk; + sparse.size = dev_desc->lba - blk; + sparse.write = mmc_sparse_write; + sparse.reserve = mmc_sparse_reserve; + sparse.mssg = NULL; + sprintf(dest, "0x" LBAF, sparse.start * sparse.blksz); + + if (write_sparse_image(&sparse, dest, addr)) + return CMD_RET_FAILURE; + else + return CMD_RET_SUCCESS; +} +#endif + static int do_mmc_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { @@ -801,6 +868,9 @@ static cmd_tbl_t cmd_mmc[] = { U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""), #if CONFIG_IS_ENABLED(MMC_WRITE) U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""), +#if defined(CONFIG_FASTBOOT_FLASH) + U_BOOT_CMD_MKENT(swrite, 3, 0, do_mmc_sparse_write, "", ""), +#endif U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""), #endif U_BOOT_CMD_MKENT(rescan, 1, 1, do_mmc_rescan, "", ""), @@ -857,6 +927,9 @@ U_BOOT_CMD( "info - display info of the current MMC device\n" "mmc read addr blk# cnt\n" "mmc write addr blk# cnt\n" +#if defined(CONFIG_FASTBOOT_FLASH) + "mmc swrite addr blk#\n" +#endif "mmc erase blk# cnt\n" "mmc rescan\n" "mmc part - lists available partition on current mmc device\n" diff --git a/cmd/smccc.c b/cmd/smccc.c new file mode 100644 index 0000000000..8b1475c2fe --- /dev/null +++ b/cmd/smccc.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 + * Michalis Pappas <mpappas@fastmail.fm> + */ +#include <asm/psci.h> +#include <common.h> +#include <command.h> +#include <linux/arm-smccc.h> +#include <linux/compiler.h> +#include <linux/psci.h> + +static int do_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct arm_smccc_res res; + + unsigned long fid; + + unsigned long a1; + unsigned long a2; + unsigned long a3; + unsigned long a4; + unsigned long a5; + unsigned long a6; + unsigned long a7; + + if (argc < 2) + return CMD_RET_USAGE; + + fid = simple_strtoul(argv[1], NULL, 16); + + a1 = argc > 2 ? simple_strtoul(argv[2], NULL, 16) : 0; + a2 = argc > 3 ? simple_strtoul(argv[3], NULL, 16) : 0; + a3 = argc > 4 ? simple_strtoul(argv[4], NULL, 16) : 0; + a4 = argc > 5 ? simple_strtoul(argv[5], NULL, 16) : 0; + a5 = argc > 6 ? simple_strtoul(argv[6], NULL, 16) : 0; + a6 = argc > 7 ? simple_strtoul(argv[7], NULL, 16) : 0; + a7 = argc > 8 ? simple_strtoul(argv[8], NULL, 16) : 0; + + if (!strcmp(argv[0], "smc")) + arm_smccc_smc(fid, a1, a2, a3, a4, a5, a6, a7, &res); + else + arm_smccc_hvc(fid, a1, a2, a3, a4, a5, a6, a7, &res); + + printf("Res: %ld %ld %ld %ld\n", res.a0, res.a1, res.a2, res.a3); + + return 0; +} + +#ifdef CONFIG_CMD_SMC +U_BOOT_CMD( + smc, 8, 2, do_call, + "Issue a Secure Monitor Call", + "<fid> [arg1 ... arg6] [id]\n" + " - fid Function ID\n" + " - arg SMC arguments, passed to X1-X6 (default to zero)\n" + " - id Secure OS ID / Session ID, passed to W7 (defaults to zero)\n" +); +#endif + +#ifdef CONFIG_CMD_HVC +U_BOOT_CMD( + hvc, 8, 2, do_call, + "Issue a Hypervisor Call", + "<fid> [arg1...arg7] [id]\n" + " - fid Function ID\n" + " - arg HVC arguments, passed to X1-X6 (default to zero)\n" + " - id Session ID, passed to W7 (defaults to zero)\n" +); +#endif + diff --git a/common/fb_mmc.c b/common/fb_mmc.c index b748b15f63..46f0073dbc 100644 --- a/common/fb_mmc.c +++ b/common/fb_mmc.c @@ -329,6 +329,7 @@ void fb_mmc_flash_write(const char *cmd, void *download_buffer, if (is_sparse_image(download_buffer)) { struct fb_mmc_sparse sparse_priv; struct sparse_storage sparse; + int err; sparse_priv.dev_desc = dev_desc; @@ -337,13 +338,15 @@ void fb_mmc_flash_write(const char *cmd, void *download_buffer, sparse.size = info.size; sparse.write = fb_mmc_sparse_write; sparse.reserve = fb_mmc_sparse_reserve; + sparse.mssg = fastboot_fail; printf("Flashing sparse image at offset " LBAFU "\n", sparse.start); sparse.priv = &sparse_priv; - write_sparse_image(&sparse, cmd, download_buffer, - download_bytes); + err = write_sparse_image(&sparse, cmd, download_buffer); + if (!err) + fastboot_okay(""); } else { write_raw_image(dev_desc, &info, cmd, download_buffer, download_bytes); diff --git a/common/fb_nand.c b/common/fb_nand.c index 3df0f7287e..c07655e49e 100644 --- a/common/fb_nand.c +++ b/common/fb_nand.c @@ -174,13 +174,15 @@ void fb_nand_flash_write(const char *cmd, void *download_buffer, sparse.size = part->size / sparse.blksz; sparse.write = fb_nand_sparse_write; sparse.reserve = fb_nand_sparse_reserve; + sparse.mssg = fastboot_fail; printf("Flashing sparse image at offset " LBAFU "\n", sparse.start); sparse.priv = &sparse_priv; - write_sparse_image(&sparse, cmd, download_buffer, - download_bytes); + ret = write_sparse_image(&sparse, cmd, download_buffer); + if (!ret) + fastboot_okay(""); } else { printf("Flashing raw image at offset 0x%llx\n", part->offset); diff --git a/common/image-sparse.c b/common/image-sparse.c index ddf5772cf8..9223b9a1b8 100644 --- a/common/image-sparse.c +++ b/common/image-sparse.c @@ -41,7 +41,6 @@ #include <malloc.h> #include <part.h> #include <sparse_format.h> -#include <fastboot.h> #include <linux/math64.h> @@ -49,9 +48,10 @@ #define CONFIG_FASTBOOT_FLASH_FILLBUF_SIZE (1024 * 512) #endif -void write_sparse_image( - struct sparse_storage *info, const char *part_name, - void *data, unsigned sz) +static void default_log(const char *ignored) {} + +int write_sparse_image(struct sparse_storage *info, + const char *part_name, void *data) { lbaint_t blk; lbaint_t blkcnt; @@ -83,6 +83,9 @@ void write_sparse_image( data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t)); } + if (!info->mssg) + info->mssg = default_log; + debug("=== Sparse Image Header ===\n"); debug("magic: 0x%x\n", sparse_header->magic); debug("major_version: 0x%x\n", sparse_header->major_version); @@ -101,8 +104,8 @@ void write_sparse_image( if (offset) { printf("%s: Sparse image block size issue [%u]\n", __func__, sparse_header->blk_sz); - fastboot_fail("sparse image block size issue"); - return; + info->mssg("sparse image block size issue"); + return -1; } puts("Flashing Sparse Image\n"); @@ -136,18 +139,16 @@ void write_sparse_image( case CHUNK_TYPE_RAW: if (chunk_header->total_sz != (sparse_header->chunk_hdr_sz + chunk_data_sz)) { - fastboot_fail( - "Bogus chunk size for chunk type Raw"); - return; + info->mssg("Bogus chunk size for chunk type Raw"); + return -1; } if (blk + blkcnt > info->start + info->size) { printf( "%s: Request would exceed partition size!\n", __func__); - fastboot_fail( - "Request would exceed partition size!"); - return; + info->mssg("Request would exceed partition size!"); + return -1; } blks = info->write(info, blk, blkcnt, data); @@ -156,9 +157,8 @@ void write_sparse_image( printf("%s: %s" LBAFU " [" LBAFU "]\n", __func__, "Write failed, block #", blk, blks); - fastboot_fail( - "flash write failure"); - return; + info->mssg("flash write failure"); + return -1; } blk += blks; bytes_written += blkcnt * info->blksz; @@ -169,9 +169,8 @@ void write_sparse_image( case CHUNK_TYPE_FILL: if (chunk_header->total_sz != (sparse_header->chunk_hdr_sz + sizeof(uint32_t))) { - fastboot_fail( - "Bogus chunk size for chunk type FILL"); - return; + info->mssg("Bogus chunk size for chunk type FILL"); + return -1; } fill_buf = (uint32_t *) @@ -180,9 +179,8 @@ void write_sparse_image( info->blksz * fill_buf_num_blks, ARCH_DMA_MINALIGN)); if (!fill_buf) { - fastboot_fail( - "Malloc failed for: CHUNK_TYPE_FILL"); - return; + info->mssg("Malloc failed for: CHUNK_TYPE_FILL"); + return -1; } fill_val = *(uint32_t *)data; @@ -198,9 +196,8 @@ void write_sparse_image( printf( "%s: Request would exceed partition size!\n", __func__); - fastboot_fail( - "Request would exceed partition size!"); - return; + info->mssg("Request would exceed partition size!"); + return -1; } for (i = 0; i < blkcnt;) { @@ -214,10 +211,9 @@ void write_sparse_image( __func__, "Write failed, block #", blk, j); - fastboot_fail( - "flash write failure"); + info->mssg("flash write failure"); free(fill_buf); - return; + return -1; } blk += blks; i += j; @@ -235,9 +231,8 @@ void write_sparse_image( case CHUNK_TYPE_CRC32: if (chunk_header->total_sz != sparse_header->chunk_hdr_sz) { - fastboot_fail( - "Bogus chunk size for chunk type Dont Care"); - return; + info->mssg("Bogus chunk size for chunk type Dont Care"); + return -1; } total_blocks += chunk_header->chunk_sz; data += chunk_data_sz; @@ -246,8 +241,8 @@ void write_sparse_image( default: printf("%s: Unknown chunk type: %x\n", __func__, chunk_header->chunk_type); - fastboot_fail("Unknown chunk type"); - return; + info->mssg("Unknown chunk type"); + return -1; } } @@ -255,10 +250,10 @@ void write_sparse_image( total_blocks, sparse_header->total_blks); printf("........ wrote %u bytes to '%s'\n", bytes_written, part_name); - if (total_blocks != sparse_header->total_blks) - fastboot_fail("sparse image write failure"); - else - fastboot_okay(""); + if (total_blocks != sparse_header->total_blks) { + info->mssg("sparse image write failure"); + return -1; + } - return; + return 0; } diff --git a/configs/sama5d2_ptc_ek_mmc_defconfig b/configs/sama5d2_ptc_ek_mmc_defconfig index 7a52c10181..9c3c57806d 100644 --- a/configs/sama5d2_ptc_ek_mmc_defconfig +++ b/configs/sama5d2_ptc_ek_mmc_defconfig @@ -7,7 +7,7 @@ CONFIG_DEFAULT_DEVICE_TREE="at91-sama5d2_ptc_ek" CONFIG_DEBUG_UART=y CONFIG_ENV_VARS_UBOOT_CONFIG=y CONFIG_FIT=y -CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2,SYS_USE_MMC" +CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2" CONFIG_SD_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_CONSOLE_MUX=y diff --git a/configs/sama5d2_ptc_ek_nandflash_defconfig b/configs/sama5d2_ptc_ek_nandflash_defconfig index 2739001cf1..94d5492f99 100644 --- a/configs/sama5d2_ptc_ek_nandflash_defconfig +++ b/configs/sama5d2_ptc_ek_nandflash_defconfig @@ -7,7 +7,7 @@ CONFIG_DEFAULT_DEVICE_TREE="at91-sama5d2_ptc_ek" CONFIG_DEBUG_UART=y CONFIG_ENV_VARS_UBOOT_CONFIG=y CONFIG_FIT=y -CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2,SYS_USE_NANDFLASH" +CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2" CONFIG_NAND_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_CONSOLE_MUX=y diff --git a/configs/sama5d36ek_cmp_nandflash_defconfig b/configs/sama5d36ek_cmp_nandflash_defconfig index de777658eb..afe29c6fbc 100644 --- a/configs/sama5d36ek_cmp_nandflash_defconfig +++ b/configs/sama5d36ek_cmp_nandflash_defconfig @@ -10,7 +10,7 @@ CONFIG_FIT=y CONFIG_NAND_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs" # CONFIG_CONSOLE_MUX is not set CONFIG_SYS_CONSOLE_IS_IN_ENV=y # CONFIG_DISPLAY_BOARDINFO is not set diff --git a/configs/sama5d36ek_cmp_spiflash_defconfig b/configs/sama5d36ek_cmp_spiflash_defconfig index 272c370a45..7c8668ec69 100644 --- a/configs/sama5d36ek_cmp_spiflash_defconfig +++ b/configs/sama5d36ek_cmp_spiflash_defconfig @@ -10,7 +10,7 @@ CONFIG_FIT=y CONFIG_SPI_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs" # CONFIG_CONSOLE_MUX is not set CONFIG_SYS_CONSOLE_IS_IN_ENV=y # CONFIG_DISPLAY_BOARDINFO is not set diff --git a/configs/sama5d3_xplained_nandflash_defconfig b/configs/sama5d3_xplained_nandflash_defconfig index 2468df914b..62716b6c4d 100644 --- a/configs/sama5d3_xplained_nandflash_defconfig +++ b/configs/sama5d3_xplained_nandflash_defconfig @@ -17,7 +17,7 @@ CONFIG_FIT=y CONFIG_NAND_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs" # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_HUSH_PARSER=y CONFIG_CMD_BOOTZ=y diff --git a/configs/sama5d3xek_nandflash_defconfig b/configs/sama5d3xek_nandflash_defconfig index 122668cb79..d71ccd42e5 100644 --- a/configs/sama5d3xek_nandflash_defconfig +++ b/configs/sama5d3xek_nandflash_defconfig @@ -17,7 +17,7 @@ CONFIG_FIT=y CONFIG_NAND_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs" # CONFIG_CONSOLE_MUX is not set CONFIG_SYS_CONSOLE_IS_IN_ENV=y # CONFIG_DISPLAY_BOARDINFO is not set diff --git a/configs/sama5d3xek_spiflash_defconfig b/configs/sama5d3xek_spiflash_defconfig index b1c2f57e81..9c36262976 100644 --- a/configs/sama5d3xek_spiflash_defconfig +++ b/configs/sama5d3xek_spiflash_defconfig @@ -18,7 +18,7 @@ CONFIG_FIT=y CONFIG_SPI_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs" # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_SPI_LOAD=y CONFIG_HUSH_PARSER=y diff --git a/configs/sama5d4_xplained_nandflash_defconfig b/configs/sama5d4_xplained_nandflash_defconfig index 478be7d720..d4f8702e56 100644 --- a/configs/sama5d4_xplained_nandflash_defconfig +++ b/configs/sama5d4_xplained_nandflash_defconfig @@ -17,7 +17,7 @@ CONFIG_FIT=y CONFIG_NAND_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs" # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_HUSH_PARSER=y CONFIG_CMD_BOOTZ=y diff --git a/configs/sama5d4_xplained_spiflash_defconfig b/configs/sama5d4_xplained_spiflash_defconfig index 96c0a3171e..2dd4c685d6 100644 --- a/configs/sama5d4_xplained_spiflash_defconfig +++ b/configs/sama5d4_xplained_spiflash_defconfig @@ -18,7 +18,7 @@ CONFIG_FIT=y CONFIG_SPI_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs" # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_SPI_LOAD=y CONFIG_HUSH_PARSER=y diff --git a/configs/sama5d4ek_nandflash_defconfig b/configs/sama5d4ek_nandflash_defconfig index e1e7466b21..df4a0dbb93 100644 --- a/configs/sama5d4ek_nandflash_defconfig +++ b/configs/sama5d4ek_nandflash_defconfig @@ -17,7 +17,7 @@ CONFIG_FIT=y CONFIG_NAND_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs" # CONFIG_CONSOLE_MUX is not set CONFIG_SYS_CONSOLE_IS_IN_ENV=y # CONFIG_DISPLAY_BOARDINFO is not set diff --git a/configs/sama5d4ek_spiflash_defconfig b/configs/sama5d4ek_spiflash_defconfig index 84ed7bc47f..0fc9c4e8f6 100644 --- a/configs/sama5d4ek_spiflash_defconfig +++ b/configs/sama5d4ek_spiflash_defconfig @@ -18,7 +18,7 @@ CONFIG_FIT=y CONFIG_SPI_BOOT=y CONFIG_BOOTDELAY=3 CONFIG_USE_BOOTARGS=y -CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,512k(uboot)ro,256K(env),256k(env_redundant),256k(spare),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=7 root=ubi0:rootfs" +CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256K(env_redundant),256k(env),512k(dtb),6M(kernel)ro,-(rootfs) rootfstype=ubifs ubi.mtd=6 root=ubi0:rootfs" # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_SPL_SPI_LOAD=y CONFIG_HUSH_PARSER=y diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 46790bbe0e..b1c3690c00 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -23,6 +23,7 @@ CONFIG_CMD_GPT=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_DOS_PARTITION is not set CONFIG_DM_I2C=y @@ -31,6 +32,11 @@ CONFIG_DM_MMC=y CONFIG_STM32_SDMMC2=y # CONFIG_SPL_PINCTRL_FULL is not set CONFIG_DM_PMIC=y +# CONFIG_SPL_PMIC_CHILDREN is not set CONFIG_PMIC_STPMU1=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_GPIO=y +CONFIG_DM_REGULATOR_STM32_VREFBUF=y +CONFIG_DM_REGULATOR_STPMU1=y CONFIG_STM32_SERIAL=y # CONFIG_EFI_LOADER is not set diff --git a/doc/device-tree-bindings/regulator/st,stm32-vrefbuf.txt b/doc/device-tree-bindings/regulator/st,stm32-vrefbuf.txt new file mode 100644 index 0000000000..0f6b6feda3 --- /dev/null +++ b/doc/device-tree-bindings/regulator/st,stm32-vrefbuf.txt @@ -0,0 +1,23 @@ +STM32 VREFBUF - Voltage reference buffer + +Some STM32 devices embed a voltage reference buffer which can be used as +voltage reference for ADCs, DACs and also as voltage reference for external +components through the dedicated VREF+ pin. + +Required properties: +- compatible: Must be "st,stm32-vrefbuf". +- reg: Offset and length of VREFBUF register set. +- clocks: Must contain an entry for peripheral clock. + +Optional properties: +- vdda-supply: Phandle to the parent vdda supply regulator node. + +Example: + vrefbuf: regulator@58003c00 { + compatible = "st,stm32-vrefbuf"; + reg = <0x58003C00 0x8>; + clocks = <&rcc VREF_CK>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2500000>; + vdda-supply = <&vdda>; + }; diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 8094420548..93e27f131c 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -29,6 +29,16 @@ config ADC_SANDBOX - 16-bit resolution - single and multi-channel conversion mode +config SARADC_MESON + bool "Enable Amlogic Meson SARADC driver" + imply REGMAP + help + This enables driver for Amlogic Meson SARADC. + It provides: + - 8 analog input channels + - 1O or 12 bits resolution + - Up to 1MSPS of sample rate + config SARADC_ROCKCHIP bool "Enable Rockchip SARADC driver" help diff --git a/drivers/adc/Makefile b/drivers/adc/Makefile index 4b5aa693ec..95c93d4c57 100644 --- a/drivers/adc/Makefile +++ b/drivers/adc/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_ADC) += adc-uclass.o obj-$(CONFIG_ADC_EXYNOS) += exynos-adc.o obj-$(CONFIG_ADC_SANDBOX) += sandbox.o obj-$(CONFIG_SARADC_ROCKCHIP) += rockchip-saradc.o +obj-$(CONFIG_SARADC_MESON) += meson-saradc.o diff --git a/drivers/adc/meson-saradc.c b/drivers/adc/meson-saradc.c new file mode 100644 index 0000000000..bcab76d050 --- /dev/null +++ b/drivers/adc/meson-saradc.c @@ -0,0 +1,723 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> + * Copyright (C) 2018 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + * + * Amlogic Meson Successive Approximation Register (SAR) A/D Converter + */ + +#include <common.h> +#include <adc.h> +#include <clk.h> +#include <dm.h> +#include <regmap.h> +#include <errno.h> +#include <asm/io.h> +#include <linux/math64.h> +#include <linux/bitfield.h> + +#define MESON_SAR_ADC_REG0 0x00 + #define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31) + #define MESON_SAR_ADC_REG0_BUSY_MASK GENMASK(30, 28) + #define MESON_SAR_ADC_REG0_DELTA_BUSY BIT(30) + #define MESON_SAR_ADC_REG0_AVG_BUSY BIT(29) + #define MESON_SAR_ADC_REG0_SAMPLE_BUSY BIT(28) + #define MESON_SAR_ADC_REG0_FIFO_FULL BIT(27) + #define MESON_SAR_ADC_REG0_FIFO_EMPTY BIT(26) + #define MESON_SAR_ADC_REG0_FIFO_COUNT_MASK GENMASK(25, 21) + #define MESON_SAR_ADC_REG0_ADC_BIAS_CTRL_MASK GENMASK(20, 19) + #define MESON_SAR_ADC_REG0_CURR_CHAN_ID_MASK GENMASK(18, 16) + #define MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL BIT(15) + #define MESON_SAR_ADC_REG0_SAMPLING_STOP BIT(14) + #define MESON_SAR_ADC_REG0_CHAN_DELTA_EN_MASK GENMASK(13, 12) + #define MESON_SAR_ADC_REG0_DETECT_IRQ_POL BIT(10) + #define MESON_SAR_ADC_REG0_DETECT_IRQ_EN BIT(9) + #define MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK GENMASK(8, 4) + #define MESON_SAR_ADC_REG0_FIFO_IRQ_EN BIT(3) + #define MESON_SAR_ADC_REG0_SAMPLING_START BIT(2) + #define MESON_SAR_ADC_REG0_CONTINUOUS_EN BIT(1) + #define MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE BIT(0) + +#define MESON_SAR_ADC_CHAN_LIST 0x04 + #define MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK GENMASK(26, 24) + #define MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(_chan) \ + (GENMASK(2, 0) << ((_chan) * 3)) + +#define MESON_SAR_ADC_AVG_CNTL 0x08 + #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan) \ + (16 + ((_chan) * 2)) + #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan) \ + (GENMASK(17, 16) << ((_chan) * 2)) + #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan) \ + (0 + ((_chan) * 2)) + #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan) \ + (GENMASK(1, 0) << ((_chan) * 2)) + +#define MESON_SAR_ADC_REG3 0x0c + #define MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY BIT(31) + #define MESON_SAR_ADC_REG3_CLK_EN BIT(30) + #define MESON_SAR_ADC_REG3_BL30_INITIALIZED BIT(28) + #define MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN BIT(27) + #define MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE BIT(26) + #define MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK GENMASK(25, 23) + #define MESON_SAR_ADC_REG3_DETECT_EN BIT(22) + #define MESON_SAR_ADC_REG3_ADC_EN BIT(21) + #define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK GENMASK(20, 18) + #define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK GENMASK(17, 16) + #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT 10 + #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 5 + #define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK GENMASK(9, 8) + #define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK GENMASK(7, 0) + +#define MESON_SAR_ADC_DELAY 0x10 + #define MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK GENMASK(25, 24) + #define MESON_SAR_ADC_DELAY_BL30_BUSY BIT(15) + #define MESON_SAR_ADC_DELAY_KERNEL_BUSY BIT(14) + #define MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK GENMASK(23, 16) + #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK GENMASK(9, 8) + #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK GENMASK(7, 0) + +#define MESON_SAR_ADC_LAST_RD 0x14 + #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK GENMASK(23, 16) + #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK GENMASK(9, 0) + +#define MESON_SAR_ADC_FIFO_RD 0x18 + #define MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK GENMASK(14, 12) + #define MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK GENMASK(11, 0) + +#define MESON_SAR_ADC_AUX_SW 0x1c + #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(_chan) \ + (8 + (((_chan) - 2) * 3)) + #define MESON_SAR_ADC_AUX_SW_VREF_P_MUX BIT(6) + #define MESON_SAR_ADC_AUX_SW_VREF_N_MUX BIT(5) + #define MESON_SAR_ADC_AUX_SW_MODE_SEL BIT(4) + #define MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW BIT(3) + #define MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW BIT(2) + #define MESON_SAR_ADC_AUX_SW_YM_DRIVE_SW BIT(1) + #define MESON_SAR_ADC_AUX_SW_XM_DRIVE_SW BIT(0) + +#define MESON_SAR_ADC_CHAN_10_SW 0x20 + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK GENMASK(25, 23) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX BIT(22) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX BIT(21) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL BIT(20) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW BIT(19) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW BIT(18) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW BIT(17) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW BIT(16) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK GENMASK(9, 7) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX BIT(6) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX BIT(5) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL BIT(4) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW BIT(3) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW BIT(2) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW BIT(1) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW BIT(0) + +#define MESON_SAR_ADC_DETECT_IDLE_SW 0x24 + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN BIT(26) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK GENMASK(25, 23) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_P_MUX BIT(22) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_N_MUX BIT(21) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL BIT(20) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YP_DRIVE_SW BIT(19) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XP_DRIVE_SW BIT(18) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YM_DRIVE_SW BIT(17) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XM_DRIVE_SW BIT(16) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK GENMASK(9, 7) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_P_MUX BIT(6) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_N_MUX BIT(5) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL BIT(4) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YP_DRIVE_SW BIT(3) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XP_DRIVE_SW BIT(2) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YM_DRIVE_SW BIT(1) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XM_DRIVE_SW BIT(0) + +#define MESON_SAR_ADC_DELTA_10 0x28 + #define MESON_SAR_ADC_DELTA_10_TEMP_SEL BIT(27) + #define MESON_SAR_ADC_DELTA_10_TS_REVE1 BIT(26) + #define MESON_SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK GENMASK(25, 16) + #define MESON_SAR_ADC_DELTA_10_TS_REVE0 BIT(15) + #define MESON_SAR_ADC_DELTA_10_TS_C_SHIFT 11 + #define MESON_SAR_ADC_DELTA_10_TS_C_MASK GENMASK(14, 11) + #define MESON_SAR_ADC_DELTA_10_TS_VBG_EN BIT(10) + #define MESON_SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK GENMASK(9, 0) + +/* + * NOTE: registers from here are undocumented (the vendor Linux kernel driver + * and u-boot source served as reference). These only seem to be relevant on + * GXBB and newer. + */ +#define MESON_SAR_ADC_REG11 0x2c + #define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13) + +#define MESON_SAR_ADC_REG13 0x34 + #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8) + +#define MESON_SAR_ADC_MAX_FIFO_SIZE 32 +#define MESON_SAR_ADC_TIMEOUT 100 /* ms */ + +#define NUM_CHANNELS 8 + +#define MILLION 1000000 + +struct meson_saradc_data { + int num_bits; +}; + +struct meson_saradc_priv { + const struct meson_saradc_data *data; + struct regmap *regmap; + struct clk core_clk; + struct clk adc_clk; + bool initialized; + int active_channel; + int calibbias; + int calibscale; +}; + +static unsigned int +meson_saradc_get_fifo_count(struct meson_saradc_priv *priv) +{ + u32 regval; + + regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); + + return FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval); +} + +static int meson_saradc_lock(struct meson_saradc_priv *priv) +{ + uint val, timeout = 10000; + + /* prevent BL30 from using the SAR ADC while we are using it */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); + + /* + * wait until BL30 releases it's lock (so we can use the SAR ADC) + */ + do { + udelay(1); + regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val); + } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--); + + if (timeout < 0) { + printf("Timeout while waiting for BL30 unlock\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void meson_saradc_unlock(struct meson_saradc_priv *priv) +{ + /* allow BL30 to use the SAR ADC again */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); +} + +static void meson_saradc_clear_fifo(struct meson_saradc_priv *priv) +{ + unsigned int count, tmp; + + for (count = 0; count < MESON_SAR_ADC_MAX_FIFO_SIZE; count++) { + if (!meson_saradc_get_fifo_count(priv)) + break; + + regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, &tmp); + } +} + +static int meson_saradc_calib_val(struct meson_saradc_priv *priv, int val) +{ + int tmp; + + /* use val_calib = scale * val_raw + offset calibration function */ + tmp = div_s64((s64)val * priv->calibscale, MILLION) + priv->calibbias; + + return clamp(tmp, 0, (1 << priv->data->num_bits) - 1); +} + +static int meson_saradc_wait_busy_clear(struct meson_saradc_priv *priv) +{ + uint regval, timeout = 10000; + + /* + * NOTE: we need a small delay before reading the status, otherwise + * the sample engine may not have started internally (which would + * seem to us that sampling is already finished). + */ + do { + udelay(1); + regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); + } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--); + + if (timeout < 0) + return -ETIMEDOUT; + + return 0; +} + +static int meson_saradc_read_raw_sample(struct meson_saradc_priv *priv, + unsigned int channel, uint *val) +{ + uint regval, fifo_chan, fifo_val, count; + int ret; + + ret = meson_saradc_wait_busy_clear(priv); + if (ret) + return ret; + + count = meson_saradc_get_fifo_count(priv); + if (count != 1) { + printf("ADC FIFO has %d element(s) instead of one\n", count); + return -EINVAL; + } + + regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, ®val); + fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval); + if (fifo_chan != channel) { + printf("ADC FIFO entry belongs to channel %d instead of %d\n", + fifo_chan, channel); + return -EINVAL; + } + + fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval); + fifo_val &= GENMASK(priv->data->num_bits - 1, 0); + *val = meson_saradc_calib_val(priv, fifo_val); + + return 0; +} + +static void meson_saradc_start_sample_engine(struct meson_saradc_priv *priv) +{ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_START, + MESON_SAR_ADC_REG0_SAMPLING_START); +} + +static void meson_saradc_stop_sample_engine(struct meson_saradc_priv *priv) +{ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_STOP, + MESON_SAR_ADC_REG0_SAMPLING_STOP); + + /* wait until all modules are stopped */ + meson_saradc_wait_busy_clear(priv); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0); +} + +enum meson_saradc_avg_mode { + NO_AVERAGING = 0x0, + MEAN_AVERAGING = 0x1, + MEDIAN_AVERAGING = 0x2, +}; + +enum meson_saradc_num_samples { + ONE_SAMPLE = 0x0, + TWO_SAMPLES = 0x1, + FOUR_SAMPLES = 0x2, + EIGHT_SAMPLES = 0x3, +}; + +static void meson_saradc_set_averaging(struct meson_saradc_priv *priv, + unsigned int channel, + enum meson_saradc_avg_mode mode, + enum meson_saradc_num_samples samples) +{ + int val; + + val = samples << MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL, + MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(channel), + val); + + val = mode << MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL, + MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(channel), val); +} + +static void meson_saradc_enable_channel(struct meson_saradc_priv *priv, + unsigned int channel) +{ + uint regval; + + /* + * the SAR ADC engine allows sampling multiple channels at the same + * time. to keep it simple we're only working with one *internal* + * channel, which starts counting at index 0 (which means: count = 1). + */ + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST, + MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval); + + /* map channel index 0 to the channel which we want to read */ + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST, + MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), regval); + + regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK, + channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW, + MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK, + regval); + + regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK, + channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW, + MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK, + regval); + + if (channel == 6) + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TEMP_SEL, 0); +} + +static int meson_saradc_get_sample(struct meson_saradc_priv *priv, + int chan, uint *val) +{ + int ret; + + ret = meson_saradc_lock(priv); + if (ret) + return ret; + + /* clear the FIFO to make sure we're not reading old values */ + meson_saradc_clear_fifo(priv); + + meson_saradc_set_averaging(priv, chan, MEAN_AVERAGING, EIGHT_SAMPLES); + + meson_saradc_enable_channel(priv, chan); + + meson_saradc_start_sample_engine(priv); + ret = meson_saradc_read_raw_sample(priv, chan, val); + meson_saradc_stop_sample_engine(priv); + + meson_saradc_unlock(priv); + + if (ret) { + printf("failed to read sample for channel %d: %d\n", + chan, ret); + return ret; + } + + return 0; +} + +static int meson_saradc_channel_data(struct udevice *dev, int channel, + unsigned int *data) +{ + struct meson_saradc_priv *priv = dev_get_priv(dev); + + if (channel != priv->active_channel) { + pr_err("Requested channel is not active!"); + return -EINVAL; + } + + return meson_saradc_get_sample(priv, channel, data); +} + +enum meson_saradc_chan7_mux_sel { + CHAN7_MUX_VSS = 0x0, + CHAN7_MUX_VDD_DIV4 = 0x1, + CHAN7_MUX_VDD_DIV2 = 0x2, + CHAN7_MUX_VDD_MUL3_DIV4 = 0x3, + CHAN7_MUX_VDD = 0x4, + CHAN7_MUX_CH7_INPUT = 0x7, +}; + +static void meson_saradc_set_chan7_mux(struct meson_saradc_priv *priv, + enum meson_saradc_chan7_mux_sel sel) +{ + u32 regval; + + regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval); + + udelay(20); +} + +static int meson_saradc_calib(struct meson_saradc_priv *priv) +{ + uint nominal0, nominal1, value0, value1; + int ret; + + /* use points 25% and 75% for calibration */ + nominal0 = (1 << priv->data->num_bits) / 4; + nominal1 = (1 << priv->data->num_bits) * 3 / 4; + + meson_saradc_set_chan7_mux(priv, CHAN7_MUX_VDD_DIV4); + udelay(20); + ret = meson_saradc_get_sample(priv, 7, &value0); + if (ret < 0) + goto out; + + meson_saradc_set_chan7_mux(priv, CHAN7_MUX_VDD_MUL3_DIV4); + udelay(20); + ret = meson_saradc_get_sample(priv, 7, &value1); + if (ret < 0) + goto out; + + if (value1 <= value0) { + ret = -EINVAL; + goto out; + } + + priv->calibscale = div_s64((nominal1 - nominal0) * (s64)MILLION, + value1 - value0); + priv->calibbias = nominal0 - div_s64((s64)value0 * priv->calibscale, + MILLION); + ret = 0; +out: + meson_saradc_set_chan7_mux(priv, CHAN7_MUX_CH7_INPUT); + + return ret; +} + +static int meson_saradc_init(struct meson_saradc_priv *priv) +{ + uint regval; + int ret, i; + + priv->calibscale = MILLION; + + /* + * make sure we start at CH7 input since the other muxes are only used + * for internal calibration. + */ + meson_saradc_set_chan7_mux(priv, CHAN7_MUX_CH7_INPUT); + + /* + * leave sampling delay and the input clocks as configured by + * BL30 to make sure BL30 gets the values it expects when + * reading the temperature sensor. + */ + regmap_read(priv->regmap, MESON_SAR_ADC_REG3, ®val); + if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED) + return 0; + + meson_saradc_stop_sample_engine(priv); + + /* update the channel 6 MUX to select the temperature sensor */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL); + + /* disable all channels by default */ + regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY, + MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY); + + /* delay between two samples = (10+1) * 1uS */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK, + 10)); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, + 0)); + + /* delay between two samples = (10+1) * 1uS */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, + 10)); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, + 1)); + + /* + * set up the input channel muxes in MESON_SAR_ADC_CHAN_10_SW + * (0 = SAR_ADC_CH0, 1 = SAR_ADC_CH1) + */ + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK, + regval); + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, 1); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, + MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, + regval); + + /* + * set up the input channel muxes in MESON_SAR_ADC_AUX_SW + * (2 = SAR_ADC_CH2, 3 = SAR_ADC_CH3, ...) and enable + * MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW and + * MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW like the vendor driver. + */ + regval = 0; + for (i = 2; i <= 7; i++) + regval |= i << MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(i); + regval |= MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW; + regval |= MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW; + regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval); + + ret = meson_saradc_lock(priv); + if (ret) + return ret; + +#if CONFIG_IS_ENABLED(CLK) + ret = clk_enable(&priv->core_clk); + if (ret) + return ret; +#endif + + regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, + MESON_SAR_ADC_REG11_BANDGAP_EN, + MESON_SAR_ADC_REG11_BANDGAP_EN); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN, + MESON_SAR_ADC_REG3_ADC_EN); + + udelay(5); + +#if CONFIG_IS_ENABLED(CLK) + ret = clk_enable(&priv->adc_clk); + if (ret) + return ret; +#endif + + meson_saradc_unlock(priv); + + ret = meson_saradc_calib(priv); + if (ret) { + printf("calibration failed\n"); + return -EIO; + } + + return 0; +} + +static int meson_saradc_start_channel(struct udevice *dev, int channel) +{ + struct meson_saradc_priv *priv = dev_get_priv(dev); + + if (channel < 0 || channel >= NUM_CHANNELS) { + printf("Requested channel is invalid!"); + return -EINVAL; + } + + if (!priv->initialized) { + int ret; + + ret = meson_saradc_init(priv); + if (ret) + return ret; + + priv->initialized = true; + } + + priv->active_channel = channel; + + return 0; +} + +static int meson_saradc_stop(struct udevice *dev) +{ + struct meson_saradc_priv *priv = dev_get_priv(dev); + + priv->active_channel = -1; + + return 0; +} + +static int meson_saradc_probe(struct udevice *dev) +{ + struct meson_saradc_priv *priv = dev_get_priv(dev); + int ret; + + ret = regmap_init_mem(dev, &priv->regmap); + if (ret) + return ret; + +#if CONFIG_IS_ENABLED(CLK) + ret = clk_get_by_name(dev, "core", &priv->core_clk); + if (ret) + return ret; + + ret = clk_get_by_name(dev, "adc_clk", &priv->adc_clk); + if (ret) + return ret; +#endif + + priv->active_channel = -1; + + return 0; +} + +int meson_saradc_ofdata_to_platdata(struct udevice *dev) +{ + struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); + struct meson_saradc_priv *priv = dev_get_priv(dev); + + priv->data = (struct meson_saradc_data *)dev_get_driver_data(dev); + + uc_pdata->data_mask = GENMASK(priv->data->num_bits - 1, 0); + uc_pdata->data_format = ADC_DATA_FORMAT_BIN; + uc_pdata->data_timeout_us = MESON_SAR_ADC_TIMEOUT * 1000; + uc_pdata->channel_mask = GENMASK(NUM_CHANNELS - 1, 0); + + return 0; +} + +static const struct adc_ops meson_saradc_ops = { + .start_channel = meson_saradc_start_channel, + .channel_data = meson_saradc_channel_data, + .stop = meson_saradc_stop, +}; + +static const struct meson_saradc_data gxbb_saradc_data = { + .num_bits = 10, +}; + +static const struct meson_saradc_data gxl_saradc_data = { + .num_bits = 12, +}; + +static const struct udevice_id meson_saradc_ids[] = { + { .compatible = "amlogic,meson-gxbb-saradc", + .data = (ulong)&gxbb_saradc_data }, + { .compatible = "amlogic,meson-gxl-saradc", + .data = (ulong)&gxl_saradc_data }, + { .compatible = "amlogic,meson-gxm-saradc", + .data = (ulong)&gxl_saradc_data }, + { } +}; + +U_BOOT_DRIVER(meson_saradc) = { + .name = "meson_saradc", + .id = UCLASS_ADC, + .of_match = meson_saradc_ids, + .ops = &meson_saradc_ops, + .probe = meson_saradc_probe, + .ofdata_to_platdata = meson_saradc_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct meson_saradc_priv), +}; diff --git a/drivers/clk/clk_stm32f.c b/drivers/clk/clk_stm32f.c index 6c1e2575ff..cbcfe3a89d 100644 --- a/drivers/clk/clk_stm32f.c +++ b/drivers/clk/clk_stm32f.c @@ -133,6 +133,7 @@ struct stm32_clk { struct stm32_pwr_regs *pwr_regs; struct stm32_clk_info info; unsigned long hse_rate; + bool pllsaip; }; #ifdef CONFIG_VIDEO_STM32 @@ -179,8 +180,12 @@ static int configure_clocks(struct udevice *dev) /* configure SDMMC clock */ if (priv->info.v2) { /*stm32f7 case */ - /* select PLLQ as 48MHz clock source */ - clrbits_le32(®s->dckcfgr2, RCC_DCKCFGRX_CK48MSEL); + if (priv->pllsaip) + /* select PLLSAIP as 48MHz clock source */ + setbits_le32(®s->dckcfgr2, RCC_DCKCFGRX_CK48MSEL); + else + /* select PLLQ as 48MHz clock source */ + clrbits_le32(®s->dckcfgr2, RCC_DCKCFGRX_CK48MSEL); /* select 48MHz as SDMMC1 clock source */ clrbits_le32(®s->dckcfgr2, RCC_DCKCFGRX_SDMMC1SEL); @@ -188,17 +193,23 @@ static int configure_clocks(struct udevice *dev) /* select 48MHz as SDMMC2 clock source */ clrbits_le32(®s->dckcfgr2, RCC_DCKCFGR2_SDMMC2SEL); } else { /* stm32f4 case */ - /* select PLLQ as 48MHz clock source */ - clrbits_le32(®s->dckcfgr, RCC_DCKCFGRX_CK48MSEL); + if (priv->pllsaip) + /* select PLLSAIP as 48MHz clock source */ + setbits_le32(®s->dckcfgr, RCC_DCKCFGRX_CK48MSEL); + else + /* select PLLQ as 48MHz clock source */ + clrbits_le32(®s->dckcfgr, RCC_DCKCFGRX_CK48MSEL); /* select 48MHz as SDMMC1 clock source */ clrbits_le32(®s->dckcfgr, RCC_DCKCFGRX_SDMMC1SEL); } -#ifdef CONFIG_VIDEO_STM32 /* - * Configure the SAI PLL to generate LTDC pixel clock + * Configure the SAI PLL to generate LTDC pixel clock and + * 48 Mhz for SDMMC and USB */ + clrsetbits_le32(®s->pllsaicfgr, RCC_PLLSAICFGR_PLLSAIP_MASK, + RCC_PLLSAICFGR_PLLSAIP_4); clrsetbits_le32(®s->pllsaicfgr, RCC_PLLSAICFGR_PLLSAIR_MASK, RCC_PLLSAICFGR_PLLSAIR_3); clrsetbits_le32(®s->pllsaicfgr, RCC_PLLSAICFGR_PLLSAIN_MASK, @@ -206,18 +217,16 @@ static int configure_clocks(struct udevice *dev) clrsetbits_le32(®s->dckcfgr, RCC_DCKCFGR_PLLSAIDIVR_MASK, RCC_DCKCFGR_PLLSAIDIVR_2 << RCC_DCKCFGR_PLLSAIDIVR_SHIFT); -#endif + /* Enable the main PLL */ setbits_le32(®s->cr, RCC_CR_PLLON); while (!(readl(®s->cr) & RCC_CR_PLLRDY)) ; -#ifdef CONFIG_VIDEO_STM32 -/* Enable the SAI PLL */ + /* Enable the SAI PLL */ setbits_le32(®s->cr, RCC_CR_PLLSAION); while (!(readl(®s->cr) & RCC_CR_PLLSAIRDY)) ; -#endif setbits_le32(®s->apb1enr, RCC_APB1ENR_PWREN); if (priv->info.has_overdrive) { @@ -617,12 +626,17 @@ static int stm32_clk_probe(struct udevice *dev) return -EINVAL; priv->base = (struct stm32_rcc_regs *)addr; + priv->pllsaip = true; switch (dev_get_driver_data(dev)) { - case STM32F4: + case STM32F42X: + priv->pllsaip = false; + /* fallback into STM32F469 case */ + case STM32F469: memcpy(&priv->info, &stm32f4_clk_info, sizeof(struct stm32_clk_info)); break; + case STM32F7: memcpy(&priv->info, &stm32f7_clk_info, sizeof(struct stm32_clk_info)); diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index ed32585eb0..1a77eba39c 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -100,6 +100,7 @@ #define RCC_USBCKSELR 0x91C #define RCC_MP_APB1ENSETR 0xA00 #define RCC_MP_APB2ENSETR 0XA08 +#define RCC_MP_APB3ENSETR 0xA10 #define RCC_MP_AHB2ENSETR 0xA18 #define RCC_MP_AHB4ENSETR 0xA28 @@ -508,6 +509,8 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), + STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3), + STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), STM32MP1_CLK_SET_CLR(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index fabcc5f53a..8e5c3bcf61 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -132,3 +132,17 @@ int regmap_write(struct regmap *map, uint offset, uint val) return 0; } + +int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val) +{ + uint reg; + int ret; + + ret = regmap_read(map, offset, ®); + if (ret) + return ret; + + reg &= ~mask; + + return regmap_write(map, offset, reg | val); +} diff --git a/drivers/gpio/atmel_pio4.c b/drivers/gpio/atmel_pio4.c index 2385dec961..95a189a50f 100644 --- a/drivers/gpio/atmel_pio4.c +++ b/drivers/gpio/atmel_pio4.c @@ -43,7 +43,7 @@ static struct atmel_pio4_port *atmel_pio4_port_base(u32 port) } static int atmel_pio4_config_io_func(u32 port, u32 pin, - u32 func, u32 use_pullup) + u32 func, u32 config) { struct atmel_pio4_port *port_base; u32 reg, mask; @@ -57,7 +57,7 @@ static int atmel_pio4_config_io_func(u32 port, u32 pin, mask = 1 << pin; reg = func; - reg |= use_pullup ? ATMEL_PIO_PUEN_MASK : 0; + reg |= config; writel(mask, &port_base->mskr); writel(reg, &port_base->cfgr); @@ -65,60 +65,60 @@ static int atmel_pio4_config_io_func(u32 port, u32 pin, return 0; } -int atmel_pio4_set_gpio(u32 port, u32 pin, u32 use_pullup) +int atmel_pio4_set_gpio(u32 port, u32 pin, u32 config) { return atmel_pio4_config_io_func(port, pin, ATMEL_PIO_CFGR_FUNC_GPIO, - use_pullup); + config); } -int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 use_pullup) +int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 config) { return atmel_pio4_config_io_func(port, pin, ATMEL_PIO_CFGR_FUNC_PERIPH_A, - use_pullup); + config); } -int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 use_pullup) +int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 config) { return atmel_pio4_config_io_func(port, pin, ATMEL_PIO_CFGR_FUNC_PERIPH_B, - use_pullup); + config); } -int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 use_pullup) +int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 config) { return atmel_pio4_config_io_func(port, pin, ATMEL_PIO_CFGR_FUNC_PERIPH_C, - use_pullup); + config); } -int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 use_pullup) +int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 config) { return atmel_pio4_config_io_func(port, pin, ATMEL_PIO_CFGR_FUNC_PERIPH_D, - use_pullup); + config); } -int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 use_pullup) +int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 config) { return atmel_pio4_config_io_func(port, pin, ATMEL_PIO_CFGR_FUNC_PERIPH_E, - use_pullup); + config); } -int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 use_pullup) +int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 config) { return atmel_pio4_config_io_func(port, pin, ATMEL_PIO_CFGR_FUNC_PERIPH_F, - use_pullup); + config); } -int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 use_pullup) +int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 config) { return atmel_pio4_config_io_func(port, pin, ATMEL_PIO_CFGR_FUNC_PERIPH_G, - use_pullup); + config); } int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value) diff --git a/drivers/led/led_gpio.c b/drivers/led/led_gpio.c index b26f7a730c..a36942b934 100644 --- a/drivers/led/led_gpio.c +++ b/drivers/led/led_gpio.c @@ -10,6 +10,7 @@ #include <led.h> #include <asm/gpio.h> #include <dm/lists.h> +#include <dm/uclass-internal.h> struct led_gpio_priv { struct gpio_desc gpio; @@ -57,11 +58,25 @@ static int led_gpio_probe(struct udevice *dev) { struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev); struct led_gpio_priv *priv = dev_get_priv(dev); + const char *default_state; + int ret; /* Ignore the top-level LED node */ if (!uc_plat->label) return 0; - return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT); + + ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_OUT); + if (ret) + return ret; + + default_state = dev_read_string(dev, "default-state"); + if (default_state) { + if (!strncmp(default_state, "on", 2)) + gpio_led_set_state(dev, LEDST_ON); + else if (!strncmp(default_state, "off", 3)) + gpio_led_set_state(dev, LEDST_OFF); + } + return 0; } static int led_gpio_remove(struct udevice *dev) @@ -103,6 +118,14 @@ static int led_gpio_bind(struct udevice *parent) return ret; uc_plat = dev_get_uclass_platdata(dev); uc_plat->label = label; + + if (ofnode_read_bool(node, "default-state")) { + struct udevice *devp; + + ret = uclass_get_device_tail(dev, 0, &devp); + if (ret) + return ret; + } } return 0; diff --git a/drivers/misc/stm32_rcc.c b/drivers/misc/stm32_rcc.c index b436900d7c..dee82c0b7b 100644 --- a/drivers/misc/stm32_rcc.c +++ b/drivers/misc/stm32_rcc.c @@ -11,9 +11,14 @@ #include <dm/device-internal.h> #include <dm/lists.h> -struct stm32_rcc_clk stm32_rcc_clk_f4 = { +struct stm32_rcc_clk stm32_rcc_clk_f42x = { .drv_name = "stm32fx_rcc_clock", - .soc = STM32F4, + .soc = STM32F42X, +}; + +struct stm32_rcc_clk stm32_rcc_clk_f469 = { + .drv_name = "stm32fx_rcc_clock", + .soc = STM32F469, }; struct stm32_rcc_clk stm32_rcc_clk_f7 = { @@ -61,7 +66,8 @@ static const struct misc_ops stm32_rcc_ops = { }; static const struct udevice_id stm32_rcc_ids[] = { - {.compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32_rcc_clk_f4 }, + {.compatible = "st,stm32f42xx-rcc", .data = (ulong)&stm32_rcc_clk_f42x }, + {.compatible = "st,stm32f469-rcc", .data = (ulong)&stm32_rcc_clk_f469 }, {.compatible = "st,stm32f746-rcc", .data = (ulong)&stm32_rcc_clk_f7 }, {.compatible = "st,stm32h743-rcc", .data = (ulong)&stm32_rcc_clk_h7 }, { } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index c20a0cc060..f59803dbd6 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -105,4 +105,11 @@ config PCIE_LAYERSCAPE PCIe controllers. The PCIe may works in RC or EP mode according to RCW[HOST_AGT_PEX] setting. +config PCIE_INTEL_FPGA + bool "Intel FPGA PCIe support" + depends on DM_PCI + help + Say Y here if you want to enable PCIe controller support on Intel + FPGA, example Stratix 10. + endif diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 72c09f4af8..4923641895 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -33,3 +33,4 @@ obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape_fixup.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o +obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o diff --git a/drivers/pci/pcie_intel_fpga.c b/drivers/pci/pcie_intel_fpga.c new file mode 100644 index 0000000000..3cdf05b314 --- /dev/null +++ b/drivers/pci/pcie_intel_fpga.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel FPGA PCIe host controller driver + * + * Copyright (C) 2013-2018 Intel Corporation. All rights reserved + * + */ + +#include <common.h> +#include <dm.h> +#include <pci.h> +#include <asm/io.h> + +#define RP_TX_REG0 0x2000 +#define RP_TX_CNTRL 0x2004 +#define RP_TX_SOP BIT(0) +#define RP_TX_EOP BIT(1) +#define RP_RXCPL_STATUS 0x200C +#define RP_RXCPL_SOP BIT(0) +#define RP_RXCPL_EOP BIT(1) +#define RP_RXCPL_REG 0x2008 +#define P2A_INT_STATUS 0x3060 +#define P2A_INT_STS_ALL 0xf +#define P2A_INT_ENABLE 0x3070 +#define RP_CAP_OFFSET 0x70 + +/* TLP configuration type 0 and 1 */ +#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ +#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ +#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */ +#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */ +#define TLP_PAYLOAD_SIZE 0x01 +#define TLP_READ_TAG 0x1d +#define TLP_WRITE_TAG 0x10 +#define RP_DEVFN 0 + +#define RP_CFG_ADDR(pcie, reg) \ + ((pcie->hip_base) + (reg) + (1 << 20)) +#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) + +#define TLP_CFGRD_DW0(pcie, bus) \ + ((((bus != pcie->first_busno) ? TLP_FMTTYPE_CFGRD0 \ + : TLP_FMTTYPE_CFGRD1) << 24) | \ + TLP_PAYLOAD_SIZE) + +#define TLP_CFGWR_DW0(pcie, bus) \ + ((((bus != pcie->first_busno) ? TLP_FMTTYPE_CFGWR0 \ + : TLP_FMTTYPE_CFGWR1) << 24) | \ + TLP_PAYLOAD_SIZE) + +#define TLP_CFG_DW1(pcie, tag, be) \ + (((TLP_REQ_ID(pcie->first_busno, RP_DEVFN)) << 16) | (tag << 8) | (be)) +#define TLP_CFG_DW2(bus, dev, fn, offset) \ + (((bus) << 24) | ((dev) << 19) | ((fn) << 16) | (offset)) + +#define TLP_COMP_STATUS(s) (((s) >> 13) & 7) +#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff) +#define TLP_HDR_SIZE 3 +#define TLP_LOOP 500 +#define DWORD_MASK 3 + +#define IS_ROOT_PORT(pcie, bdf) \ + ((PCI_BUS(bdf) == pcie->first_busno) ? true : false) + +#define PCI_EXP_LNKSTA 18 /* Link Status */ +#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ + +/** + * struct intel_fpga_pcie - Intel FPGA PCIe controller state + * @bus: Pointer to the PCI bus + * @cra_base: The base address of CRA register space + * @hip_base: The base address of Rootport configuration space + * @first_busno: This driver supports multiple PCIe controllers. + * first_busno stores the bus number of the PCIe root-port + * number which may vary depending on the PCIe setup. + */ +struct intel_fpga_pcie { + struct udevice *bus; + void __iomem *cra_base; + void __iomem *hip_base; + int first_busno; +}; + +/** + * Intel FPGA PCIe port uses BAR0 of RC's configuration space as the + * translation from PCI bus to native BUS. Entire DDR region is mapped + * into PCIe space using these registers, so it can be reached by DMA from + * EP devices. + * The BAR0 of bridge should be hidden during enumeration to avoid the + * sizing and resource allocation by PCIe core. + */ +static bool intel_fpga_pcie_hide_rc_bar(struct intel_fpga_pcie *pcie, + pci_dev_t bdf, int offset) +{ + if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) == 0 && + PCI_FUNC(bdf) == 0 && offset == PCI_BASE_ADDRESS_0) + return true; + + return false; +} + +static inline void cra_writel(struct intel_fpga_pcie *pcie, const u32 value, + const u32 reg) +{ + writel(value, pcie->cra_base + reg); +} + +static inline u32 cra_readl(struct intel_fpga_pcie *pcie, const u32 reg) +{ + return readl(pcie->cra_base + reg); +} + +static bool intel_fpga_pcie_link_up(struct intel_fpga_pcie *pcie) +{ + return !!(readw(RP_CFG_ADDR(pcie, RP_CAP_OFFSET + PCI_EXP_LNKSTA)) + & PCI_EXP_LNKSTA_DLLLA); +} + +static bool intel_fpga_pcie_addr_valid(struct intel_fpga_pcie *pcie, + pci_dev_t bdf) +{ + /* If there is no link, then there is no device */ + if (!IS_ROOT_PORT(pcie, bdf) && !intel_fpga_pcie_link_up(pcie)) + return false; + + /* access only one slot on each root port */ + if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) > 0) + return false; + + if ((PCI_BUS(bdf) == pcie->first_busno + 1) && PCI_DEV(bdf) > 0) + return false; + + return true; +} + +static void tlp_write_tx(struct intel_fpga_pcie *pcie, u32 reg0, u32 ctrl) +{ + cra_writel(pcie, reg0, RP_TX_REG0); + cra_writel(pcie, ctrl, RP_TX_CNTRL); +} + +static int tlp_read_packet(struct intel_fpga_pcie *pcie, u32 *value) +{ + int i; + u32 ctrl; + u32 comp_status; + u32 dw[4]; + u32 count = 0; + + for (i = 0; i < TLP_LOOP; i++) { + ctrl = cra_readl(pcie, RP_RXCPL_STATUS); + if (!(ctrl & RP_RXCPL_SOP)) + continue; + + /* read first DW */ + dw[count++] = cra_readl(pcie, RP_RXCPL_REG); + + /* Poll for EOP */ + for (i = 0; i < TLP_LOOP; i++) { + ctrl = cra_readl(pcie, RP_RXCPL_STATUS); + dw[count++] = cra_readl(pcie, RP_RXCPL_REG); + if (ctrl & RP_RXCPL_EOP) { + comp_status = TLP_COMP_STATUS(dw[1]); + if (comp_status) + return -EFAULT; + + if (value && + TLP_BYTE_COUNT(dw[1]) == sizeof(u32) && + count >= 3) + *value = dw[3]; + + return 0; + } + } + + udelay(5); + } + + dev_err(pcie->dev, "read TLP packet timed out\n"); + return -ENODEV; +} + +static void tlp_write_packet(struct intel_fpga_pcie *pcie, u32 *headers, + u32 data) +{ + tlp_write_tx(pcie, headers[0], RP_TX_SOP); + + tlp_write_tx(pcie, headers[1], 0); + + tlp_write_tx(pcie, headers[2], 0); + + tlp_write_tx(pcie, data, RP_TX_EOP); +} + +static int tlp_cfg_dword_read(struct intel_fpga_pcie *pcie, pci_dev_t bdf, + int offset, u8 byte_en, u32 *value) +{ + u32 headers[TLP_HDR_SIZE]; + u8 busno = PCI_BUS(bdf); + + headers[0] = TLP_CFGRD_DW0(pcie, busno); + headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en); + headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); + + tlp_write_packet(pcie, headers, 0); + + return tlp_read_packet(pcie, value); +} + +static int tlp_cfg_dword_write(struct intel_fpga_pcie *pcie, pci_dev_t bdf, + int offset, u8 byte_en, u32 value) +{ + u32 headers[TLP_HDR_SIZE]; + u8 busno = PCI_BUS(bdf); + + headers[0] = TLP_CFGWR_DW0(pcie, busno); + headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en); + headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); + + tlp_write_packet(pcie, headers, value); + + return tlp_read_packet(pcie, NULL); +} + +int intel_fpga_rp_conf_addr(struct udevice *bus, pci_dev_t bdf, + uint offset, void **paddress) +{ + struct intel_fpga_pcie *pcie = dev_get_priv(bus); + + *paddress = RP_CFG_ADDR(pcie, offset); + + return 0; +} + +static int intel_fpga_pcie_rp_rd_conf(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + return pci_generic_mmap_read_config(bus, intel_fpga_rp_conf_addr, + bdf, offset, valuep, size); +} + +static int intel_fpga_pcie_rp_wr_conf(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + int ret; + struct intel_fpga_pcie *pcie = dev_get_priv(bus); + + ret = pci_generic_mmap_write_config(bus, intel_fpga_rp_conf_addr, + bdf, offset, value, size); + if (!ret) { + /* Monitor changes to PCI_PRIMARY_BUS register on root port + * and update local copy of root bus number accordingly. + */ + if (offset == PCI_PRIMARY_BUS) + pcie->first_busno = (u8)(value); + } + + return ret; +} + +static u8 pcie_get_byte_en(uint offset, enum pci_size_t size) +{ + switch (size) { + case PCI_SIZE_8: + return 1 << (offset & 3); + case PCI_SIZE_16: + return 3 << (offset & 3); + default: + return 0xf; + } +} + +static int _pcie_intel_fpga_read_config(struct intel_fpga_pcie *pcie, + pci_dev_t bdf, uint offset, + ulong *valuep, enum pci_size_t size) +{ + int ret; + u32 data; + u8 byte_en; + + /* Uses memory mapped method to read rootport config registers */ + if (IS_ROOT_PORT(pcie, bdf)) + return intel_fpga_pcie_rp_rd_conf(pcie->bus, bdf, + offset, valuep, size); + + byte_en = pcie_get_byte_en(offset, size); + ret = tlp_cfg_dword_read(pcie, bdf, offset & ~DWORD_MASK, + byte_en, &data); + if (ret) + return ret; + + dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n", + offset, size, data); + *valuep = pci_conv_32_to_size(data, offset, size); + + return 0; +} + +static int _pcie_intel_fpga_write_config(struct intel_fpga_pcie *pcie, + pci_dev_t bdf, uint offset, + ulong value, enum pci_size_t size) +{ + u32 data; + u8 byte_en; + + dev_dbg(pcie->dev, "PCIE CFG write: (b.d.f)=(%02d.%02d.%02d)\n", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", + offset, size, value); + + /* Uses memory mapped method to read rootport config registers */ + if (IS_ROOT_PORT(pcie, bdf)) + return intel_fpga_pcie_rp_wr_conf(pcie->bus, bdf, offset, + value, size); + + byte_en = pcie_get_byte_en(offset, size); + data = pci_conv_size_to_32(0, value, offset, size); + + return tlp_cfg_dword_write(pcie, bdf, offset & ~DWORD_MASK, + byte_en, data); +} + +static int pcie_intel_fpga_read_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + struct intel_fpga_pcie *pcie = dev_get_priv(bus); + + dev_dbg(pcie->dev, "PCIE CFG read: (b.d.f)=(%02d.%02d.%02d)\n", + PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); + + if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) { + *valuep = (u32)pci_get_ff(size); + return 0; + } + + if (!intel_fpga_pcie_addr_valid(pcie, bdf)) { + *valuep = (u32)pci_get_ff(size); + return 0; + } + + return _pcie_intel_fpga_read_config(pcie, bdf, offset, valuep, size); +} + +static int pcie_intel_fpga_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + struct intel_fpga_pcie *pcie = dev_get_priv(bus); + + if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) + return 0; + + if (!intel_fpga_pcie_addr_valid(pcie, bdf)) + return 0; + + return _pcie_intel_fpga_write_config(pcie, bdf, offset, value, + size); +} + +static int pcie_intel_fpga_probe(struct udevice *dev) +{ + struct intel_fpga_pcie *pcie = dev_get_priv(dev); + + pcie->bus = pci_get_controller(dev); + pcie->first_busno = dev->seq; + + /* clear all interrupts */ + cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS); + /* disable all interrupts */ + cra_writel(pcie, 0, P2A_INT_ENABLE); + + return 0; +} + +static int pcie_intel_fpga_ofdata_to_platdata(struct udevice *dev) +{ + struct intel_fpga_pcie *pcie = dev_get_priv(dev); + struct fdt_resource reg_res; + int node = dev_of_offset(dev); + int ret; + + DECLARE_GLOBAL_DATA_PTR; + + ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", + "Cra", ®_res); + if (ret) { + dev_err(dev, "resource \"Cra\" not found\n"); + return ret; + } + + pcie->cra_base = map_physmem(reg_res.start, + fdt_resource_size(®_res), + MAP_NOCACHE); + + ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", + "Hip", ®_res); + if (ret) { + dev_err(dev, "resource \"Hip\" not found\n"); + return ret; + } + + pcie->hip_base = map_physmem(reg_res.start, + fdt_resource_size(®_res), + MAP_NOCACHE); + + return 0; +} + +static const struct dm_pci_ops pcie_intel_fpga_ops = { + .read_config = pcie_intel_fpga_read_config, + .write_config = pcie_intel_fpga_write_config, +}; + +static const struct udevice_id pcie_intel_fpga_ids[] = { + { .compatible = "altr,pcie-root-port-2.0" }, + {}, +}; + +U_BOOT_DRIVER(pcie_intel_fpga) = { + .name = "pcie_intel_fpga", + .id = UCLASS_PCI, + .of_match = pcie_intel_fpga_ids, + .ops = &pcie_intel_fpga_ops, + .ofdata_to_platdata = pcie_intel_fpga_ofdata_to_platdata, + .probe = pcie_intel_fpga_probe, + .priv_auto_alloc_size = sizeof(struct intel_fpga_pcie), +}; diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c index 6e94d3bc28..a8e47e3c4e 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c @@ -13,7 +13,7 @@ #include "pinctrl-meson.h" -#define EE_OFF 14 +#define EE_OFF 15 static const unsigned int emmc_nand_d07_pins[] = { PIN(BOOT_0, EE_OFF), PIN(BOOT_1, EE_OFF), PIN(BOOT_2, EE_OFF), @@ -318,8 +318,6 @@ static const char * const gpio_periphs_groups[] = { "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14", "GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19", "GPIOX_20", "GPIOX_21", "GPIOX_22", - - "GPIO_TEST_N", }; static const char * const emmc_groups[] = { @@ -354,6 +352,8 @@ static const char * const gpio_aobus_groups[] = { "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4", "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9", "GPIOAO_10", "GPIOAO_11", "GPIOAO_12", "GPIOAO_13", + + "GPIO_TEST_N", }; static const char * const uart_ao_groups[] = { @@ -409,11 +409,11 @@ static struct meson_bank meson_gxbb_aobus_banks[] = { struct meson_pinctrl_data meson_gxbb_periphs_pinctrl_data = { .name = "periphs-banks", - .pin_base = 14, + .pin_base = 15, .groups = meson_gxbb_periphs_groups, .funcs = meson_gxbb_periphs_functions, .banks = meson_gxbb_periphs_banks, - .num_pins = 120, + .num_pins = 119, .num_groups = ARRAY_SIZE(meson_gxbb_periphs_groups), .num_funcs = ARRAY_SIZE(meson_gxbb_periphs_functions), .num_banks = ARRAY_SIZE(meson_gxbb_periphs_banks), @@ -425,7 +425,7 @@ struct meson_pinctrl_data meson_gxbb_aobus_pinctrl_data = { .groups = meson_gxbb_aobus_groups, .funcs = meson_gxbb_aobus_functions, .banks = meson_gxbb_aobus_banks, - .num_pins = 14, + .num_pins = 15, .num_groups = ARRAY_SIZE(meson_gxbb_aobus_groups), .num_funcs = ARRAY_SIZE(meson_gxbb_aobus_functions), .num_banks = ARRAY_SIZE(meson_gxbb_aobus_banks), diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c index fd60bc611d..ba6e3531d9 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c @@ -13,7 +13,7 @@ #include "pinctrl-meson.h" -#define EE_OFF 10 +#define EE_OFF 11 static const unsigned int emmc_nand_d07_pins[] = { PIN(BOOT_0, EE_OFF), PIN(BOOT_1, EE_OFF), PIN(BOOT_2, EE_OFF), @@ -289,7 +289,7 @@ static struct meson_pmx_group meson_gxl_periphs_groups[] = { GPIO_GROUP(GPIOCLK_0, EE_OFF), GPIO_GROUP(GPIOCLK_1, EE_OFF), - GPIO_GROUP(GPIO_TEST_N, EE_OFF), + GPIO_GROUP(GPIO_TEST_N, 0), /* Bank X */ GROUP(sdio_d0, 5, 31), @@ -471,8 +471,6 @@ static const char * const gpio_periphs_groups[] = { "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9", "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14", "GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", - - "GPIO_TEST_N", }; static const char * const emmc_groups[] = { @@ -587,6 +585,8 @@ static const char * const tsin_a_groups[] = { static const char * const gpio_aobus_groups[] = { "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4", "GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9", + + "GPIO_TEST_N", }; static const char * const uart_ao_groups[] = { @@ -691,11 +691,11 @@ static struct meson_bank meson_gxl_aobus_banks[] = { struct meson_pinctrl_data meson_gxl_periphs_pinctrl_data = { .name = "periphs-banks", - .pin_base = 10, + .pin_base = 11, .groups = meson_gxl_periphs_groups, .funcs = meson_gxl_periphs_functions, .banks = meson_gxl_periphs_banks, - .num_pins = 101, + .num_pins = 100, .num_groups = ARRAY_SIZE(meson_gxl_periphs_groups), .num_funcs = ARRAY_SIZE(meson_gxl_periphs_functions), .num_banks = ARRAY_SIZE(meson_gxl_periphs_banks), @@ -707,7 +707,7 @@ struct meson_pinctrl_data meson_gxl_aobus_pinctrl_data = { .groups = meson_gxl_aobus_groups, .funcs = meson_gxl_aobus_functions, .banks = meson_gxl_aobus_banks, - .num_pins = 10, + .num_pins = 11, .num_groups = ARRAY_SIZE(meson_gxl_aobus_groups), .num_funcs = ARRAY_SIZE(meson_gxl_aobus_functions), .num_banks = ARRAY_SIZE(meson_gxl_aobus_banks), diff --git a/drivers/power/pmic/stpmu1.c b/drivers/power/pmic/stpmu1.c index a765c4f2e9..82351b6613 100644 --- a/drivers/power/pmic/stpmu1.c +++ b/drivers/power/pmic/stpmu1.c @@ -12,6 +12,17 @@ #define STMPU1_NUM_OF_REGS 0x100 +#ifndef CONFIG_SPL_BUILD +static const struct pmic_child_info stpmu1_children_info[] = { + { .prefix = "ldo", .driver = "stpmu1_ldo" }, + { .prefix = "buck", .driver = "stpmu1_buck" }, + { .prefix = "vref_ddr", .driver = "stpmu1_vref_ddr" }, + { .prefix = "pwr_sw", .driver = "stpmu1_pwr_sw" }, + { .prefix = "boost", .driver = "stpmu1_boost" }, + { }, +}; +#endif /* CONFIG_SPL_BUILD */ + static int stpmu1_reg_count(struct udevice *dev) { return STMPU1_NUM_OF_REGS; @@ -42,6 +53,28 @@ static int stpmu1_read(struct udevice *dev, uint reg, uint8_t *buff, int len) return ret; } +static int stpmu1_bind(struct udevice *dev) +{ +#ifndef CONFIG_SPL_BUILD + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + dev_dbg(dev, "regulators subnode not found!"); + return -ENXIO; + } + dev_dbg(dev, "found regulators subnode\n"); + + children = pmic_bind_children(dev, regulators_node, + stpmu1_children_info); + if (!children) + dev_dbg(dev, "no child found\n"); +#endif /* CONFIG_SPL_BUILD */ + + return 0; +} + static struct dm_pmic_ops stpmu1_ops = { .reg_count = stpmu1_reg_count, .read = stpmu1_read, @@ -57,5 +90,6 @@ U_BOOT_DRIVER(pmic_stpmu1) = { .name = "stpmu1_pmic", .id = UCLASS_PMIC, .of_match = stpmu1_ids, + .bind = stpmu1_bind, .ops = &stpmu1_ops, }; diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 5b4ac10462..414f4a53f7 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -197,6 +197,15 @@ config DM_REGULATOR_LP87565 be configured in multi phase modes. The driver implements get/set api for value and enable. +config DM_REGULATOR_STM32_VREFBUF + bool "Enable driver for STMicroelectronics STM32 VREFBUF" + depends on DM_REGULATOR && (STM32H7 || ARCH_STM32MP) + help + This driver supports STMicroelectronics STM32 VREFBUF (voltage + reference buffer) which can be used as voltage reference for + internal ADCs, DACs and also for external components through + dedicated Vref+ pin. + config DM_REGULATOR_TPS65910 bool "Enable driver for TPS65910 PMIC regulators" depends on DM_PMIC_TPS65910 @@ -204,3 +213,12 @@ config DM_REGULATOR_TPS65910 The TPS65910 PMIC provides 4 SMPSs and 8 LDOs. This driver supports all regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements the get/set api for value and enable. + +config DM_REGULATOR_STPMU1 + bool "Enable driver for STPMU1 regulators" + depends on DM_REGULATOR && PMIC_STPMU1 + ---help--- + Enable support for the regulator functions of the STPMU1 PMIC. The + driver implements get/set api for the various BUCKS and LDOs supported + by the PMIC device. This driver is controlled by a device tree node + which includes voltage limits. diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index f7873ad27a..16208af069 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -22,4 +22,6 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMU1) += stpmu1.o diff --git a/drivers/power/regulator/stm32-vrefbuf.c b/drivers/power/regulator/stm32-vrefbuf.c new file mode 100644 index 0000000000..0ad6833ed0 --- /dev/null +++ b/drivers/power/regulator/stm32-vrefbuf.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author: Fabrice Gasnier <fabrice.gasnier@st.com> + * + * Originally based on the Linux kernel v4.16 drivers/regulator/stm32-vrefbuf.c + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <asm/io.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <power/regulator.h> + +/* STM32 VREFBUF registers */ +#define STM32_VREFBUF_CSR 0x00 + +/* STM32 VREFBUF CSR bitfields */ +#define STM32_VRS GENMASK(6, 4) +#define STM32_VRS_SHIFT 4 +#define STM32_VRR BIT(3) +#define STM32_HIZ BIT(1) +#define STM32_ENVR BIT(0) + +struct stm32_vrefbuf { + void __iomem *base; + struct clk clk; + struct udevice *vdda_supply; +}; + +static const unsigned int stm32_vrefbuf_voltages[] = { + /* Matches resp. VRS = 000b, 001b, 010b, 011b */ + 2500000, 2048000, 1800000, 1500000, +}; + +static int stm32_vrefbuf_set_enable(struct udevice *dev, bool enable) +{ + struct stm32_vrefbuf *priv = dev_get_priv(dev); + u32 val; + int ret; + + clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_HIZ | STM32_ENVR, + enable ? STM32_ENVR : STM32_HIZ); + if (!enable) + return 0; + + /* + * Vrefbuf startup time depends on external capacitor: wait here for + * VRR to be set. That means output has reached expected value. + * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as + * arbitrary timeout. + */ + ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val, + val & STM32_VRR, 10000); + if (ret < 0) { + dev_err(dev, "stm32 vrefbuf timed out: %d\n", ret); + clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, STM32_ENVR, + STM32_HIZ); + return ret; + } + + return 0; +} + +static int stm32_vrefbuf_get_enable(struct udevice *dev) +{ + struct stm32_vrefbuf *priv = dev_get_priv(dev); + + return readl(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR; +} + +static int stm32_vrefbuf_set_value(struct udevice *dev, int uV) +{ + struct stm32_vrefbuf *priv = dev_get_priv(dev); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(stm32_vrefbuf_voltages); i++) { + if (uV == stm32_vrefbuf_voltages[i]) { + clrsetbits_le32(priv->base + STM32_VREFBUF_CSR, + STM32_VRS, i << STM32_VRS_SHIFT); + return 0; + } + } + + return -EINVAL; +} + +static int stm32_vrefbuf_get_value(struct udevice *dev) +{ + struct stm32_vrefbuf *priv = dev_get_priv(dev); + u32 val; + + val = readl(priv->base + STM32_VREFBUF_CSR) & STM32_VRS; + val >>= STM32_VRS_SHIFT; + + return stm32_vrefbuf_voltages[val]; +} + +static const struct dm_regulator_ops stm32_vrefbuf_ops = { + .get_value = stm32_vrefbuf_get_value, + .set_value = stm32_vrefbuf_set_value, + .get_enable = stm32_vrefbuf_get_enable, + .set_enable = stm32_vrefbuf_set_enable, +}; + +static int stm32_vrefbuf_probe(struct udevice *dev) +{ + struct stm32_vrefbuf *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_read_addr_ptr(dev); + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret) { + dev_err(dev, "Can't get clock: %d\n", ret); + return ret; + } + + ret = clk_enable(&priv->clk); + if (ret) { + dev_err(dev, "Can't enable clock: %d\n", ret); + return ret; + } + + ret = device_get_supply_regulator(dev, "vdda-supply", + &priv->vdda_supply); + if (ret) { + dev_dbg(dev, "No vdda-supply: %d\n", ret); + return 0; + } + + ret = regulator_set_enable(priv->vdda_supply, true); + if (ret) { + dev_err(dev, "Can't enable vdda-supply: %d\n", ret); + clk_disable(&priv->clk); + } + + return ret; +} + +static const struct udevice_id stm32_vrefbuf_ids[] = { + { .compatible = "st,stm32-vrefbuf" }, + { } +}; + +U_BOOT_DRIVER(stm32_vrefbuf) = { + .name = "stm32-vrefbuf", + .id = UCLASS_REGULATOR, + .of_match = stm32_vrefbuf_ids, + .probe = stm32_vrefbuf_probe, + .ops = &stm32_vrefbuf_ops, + .priv_auto_alloc_size = sizeof(struct stm32_vrefbuf), +}; diff --git a/drivers/power/regulator/stpmu1.c b/drivers/power/regulator/stpmu1.c new file mode 100644 index 0000000000..2dedb80acc --- /dev/null +++ b/drivers/power/regulator/stpmu1.c @@ -0,0 +1,667 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * Author: Christophe Kerello <christophe.kerello@st.com> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/stpmu1.h> + +struct stpmu1_range { + int min_uv; + int min_sel; + int max_sel; + int step; +}; + +struct stpmu1_output_range { + const struct stpmu1_range *ranges; + int nbranges; +}; + +#define STPMU1_MODE(_id, _val, _name) { \ + .id = _id, \ + .register_value = _val, \ + .name = _name, \ +} + +#define STPMU1_RANGE(_min_uv, _min_sel, _max_sel, _step) { \ + .min_uv = _min_uv, \ + .min_sel = _min_sel, \ + .max_sel = _max_sel, \ + .step = _step, \ +} + +#define STPMU1_OUTPUT_RANGE(_ranges, _nbranges) { \ + .ranges = _ranges, \ + .nbranges = _nbranges, \ +} + +static int stpmu1_output_find_uv(int sel, + const struct stpmu1_output_range *output_range) +{ + const struct stpmu1_range *range; + int i; + + for (i = 0, range = output_range->ranges; + i < output_range->nbranges; i++, range++) { + if (sel >= range->min_sel && sel <= range->max_sel) + return range->min_uv + + (sel - range->min_sel) * range->step; + } + + return -EINVAL; +} + +static int stpmu1_output_find_sel(int uv, + const struct stpmu1_output_range *output_range) +{ + const struct stpmu1_range *range; + int i; + + for (i = 0, range = output_range->ranges; + i < output_range->nbranges; i++, range++) { + if (uv == range->min_uv && !range->step) + return range->min_sel; + + if (uv >= range->min_uv && + uv <= range->min_uv + + (range->max_sel - range->min_sel) * range->step) + return range->min_sel + + (uv - range->min_uv) / range->step; + } + + return -EINVAL; +} + +/* + * BUCK regulators + */ + +static const struct stpmu1_range buck1_ranges[] = { + STPMU1_RANGE(600000, 0, 30, 25000), + STPMU1_RANGE(1350000, 31, 63, 0), +}; + +static const struct stpmu1_range buck2_ranges[] = { + STPMU1_RANGE(1000000, 0, 17, 0), + STPMU1_RANGE(1050000, 18, 19, 0), + STPMU1_RANGE(1100000, 20, 21, 0), + STPMU1_RANGE(1150000, 22, 23, 0), + STPMU1_RANGE(1200000, 24, 25, 0), + STPMU1_RANGE(1250000, 26, 27, 0), + STPMU1_RANGE(1300000, 28, 29, 0), + STPMU1_RANGE(1350000, 30, 31, 0), + STPMU1_RANGE(1400000, 32, 33, 0), + STPMU1_RANGE(1450000, 34, 35, 0), + STPMU1_RANGE(1500000, 36, 63, 0), +}; + +static const struct stpmu1_range buck3_ranges[] = { + STPMU1_RANGE(1000000, 0, 19, 0), + STPMU1_RANGE(1100000, 20, 23, 0), + STPMU1_RANGE(1200000, 24, 27, 0), + STPMU1_RANGE(1300000, 28, 31, 0), + STPMU1_RANGE(1400000, 32, 35, 0), + STPMU1_RANGE(1500000, 36, 55, 100000), + STPMU1_RANGE(3400000, 56, 63, 0), +}; + +static const struct stpmu1_range buck4_ranges[] = { + STPMU1_RANGE(600000, 0, 27, 25000), + STPMU1_RANGE(1300000, 28, 29, 0), + STPMU1_RANGE(1350000, 30, 31, 0), + STPMU1_RANGE(1400000, 32, 33, 0), + STPMU1_RANGE(1450000, 34, 35, 0), + STPMU1_RANGE(1500000, 36, 60, 100000), + STPMU1_RANGE(3900000, 61, 63, 0), +}; + +/* BUCK: 1,2,3,4 - voltage ranges */ +static const struct stpmu1_output_range buck_voltage_range[] = { + STPMU1_OUTPUT_RANGE(buck1_ranges, ARRAY_SIZE(buck1_ranges)), + STPMU1_OUTPUT_RANGE(buck2_ranges, ARRAY_SIZE(buck2_ranges)), + STPMU1_OUTPUT_RANGE(buck3_ranges, ARRAY_SIZE(buck3_ranges)), + STPMU1_OUTPUT_RANGE(buck4_ranges, ARRAY_SIZE(buck4_ranges)), +}; + +/* BUCK modes */ +static const struct dm_regulator_mode buck_modes[] = { + STPMU1_MODE(STPMU1_BUCK_MODE_HP, STPMU1_BUCK_MODE_HP, "HP"), + STPMU1_MODE(STPMU1_BUCK_MODE_LP, STPMU1_BUCK_MODE_LP, "LP"), +}; + +static int stpmu1_buck_get_uv(struct udevice *dev, int buck) +{ + int sel; + + sel = pmic_reg_read(dev, STPMU1_BUCKX_CTRL_REG(buck)); + if (sel < 0) + return sel; + + sel &= STPMU1_BUCK_OUTPUT_MASK; + sel >>= STPMU1_BUCK_OUTPUT_SHIFT; + + return stpmu1_output_find_uv(sel, &buck_voltage_range[buck]); +} + +static int stpmu1_buck_get_value(struct udevice *dev) +{ + return stpmu1_buck_get_uv(dev->parent, dev->driver_data - 1); +} + +static int stpmu1_buck_set_value(struct udevice *dev, int uv) +{ + int sel, buck = dev->driver_data - 1; + + sel = stpmu1_output_find_sel(uv, &buck_voltage_range[buck]); + if (sel < 0) + return sel; + + return pmic_clrsetbits(dev->parent, + STPMU1_BUCKX_CTRL_REG(buck), + STPMU1_BUCK_OUTPUT_MASK, + sel << STPMU1_BUCK_OUTPUT_SHIFT); +} + +static int stpmu1_buck_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, + STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1)); + if (ret < 0) + return false; + + return ret & STPMU1_BUCK_EN ? true : false; +} + +static int stpmu1_buck_set_enable(struct udevice *dev, bool enable) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + int ret, uv; + + /* if regulator is already in the wanted state, nothing to do */ + if (stpmu1_buck_get_enable(dev) == enable) + return 0; + + if (enable) { + uc_pdata = dev_get_uclass_platdata(dev); + uv = stpmu1_buck_get_value(dev); + if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV)) + stpmu1_buck_set_value(dev, uc_pdata->min_uV); + } + + ret = pmic_clrsetbits(dev->parent, + STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1), + STPMU1_BUCK_EN, enable ? STPMU1_BUCK_EN : 0); + if (enable) + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + return ret; +} + +static int stpmu1_buck_get_mode(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, + STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1)); + if (ret < 0) + return ret; + + return ret & STPMU1_BUCK_MODE ? STPMU1_BUCK_MODE_LP : + STPMU1_BUCK_MODE_HP; +} + +static int stpmu1_buck_set_mode(struct udevice *dev, int mode) +{ + return pmic_clrsetbits(dev->parent, + STPMU1_BUCKX_CTRL_REG(dev->driver_data - 1), + STPMU1_BUCK_MODE, + mode ? STPMU1_BUCK_MODE : 0); +} + +static int stpmu1_buck_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + if (!dev->driver_data || dev->driver_data > STPMU1_MAX_BUCK) + return -EINVAL; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_BUCK; + uc_pdata->mode = (struct dm_regulator_mode *)buck_modes; + uc_pdata->mode_count = ARRAY_SIZE(buck_modes); + + return 0; +} + +static const struct dm_regulator_ops stpmu1_buck_ops = { + .get_value = stpmu1_buck_get_value, + .set_value = stpmu1_buck_set_value, + .get_enable = stpmu1_buck_get_enable, + .set_enable = stpmu1_buck_set_enable, + .get_mode = stpmu1_buck_get_mode, + .set_mode = stpmu1_buck_set_mode, +}; + +U_BOOT_DRIVER(stpmu1_buck) = { + .name = "stpmu1_buck", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_buck_ops, + .probe = stpmu1_buck_probe, +}; + +/* + * LDO regulators + */ + +static const struct stpmu1_range ldo12_ranges[] = { + STPMU1_RANGE(1700000, 0, 7, 0), + STPMU1_RANGE(1700000, 8, 24, 100000), + STPMU1_RANGE(3300000, 25, 31, 0), +}; + +static const struct stpmu1_range ldo3_ranges[] = { + STPMU1_RANGE(1700000, 0, 7, 0), + STPMU1_RANGE(1700000, 8, 24, 100000), + STPMU1_RANGE(3300000, 25, 30, 0), + /* Sel 31 is special case when LDO3 is in mode sync_source (BUCK2/2) */ +}; + +static const struct stpmu1_range ldo5_ranges[] = { + STPMU1_RANGE(1700000, 0, 7, 0), + STPMU1_RANGE(1700000, 8, 30, 100000), + STPMU1_RANGE(3900000, 31, 31, 0), +}; + +static const struct stpmu1_range ldo6_ranges[] = { + STPMU1_RANGE(900000, 0, 24, 100000), + STPMU1_RANGE(3300000, 25, 31, 0), +}; + +/* LDO: 1,2,3,4,5,6 - voltage ranges */ +static const struct stpmu1_output_range ldo_voltage_range[] = { + STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), + STPMU1_OUTPUT_RANGE(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)), + STPMU1_OUTPUT_RANGE(ldo3_ranges, ARRAY_SIZE(ldo3_ranges)), + STPMU1_OUTPUT_RANGE(NULL, 0), + STPMU1_OUTPUT_RANGE(ldo5_ranges, ARRAY_SIZE(ldo5_ranges)), + STPMU1_OUTPUT_RANGE(ldo6_ranges, ARRAY_SIZE(ldo6_ranges)), +}; + +/* LDO modes */ +static const struct dm_regulator_mode ldo_modes[] = { + STPMU1_MODE(STPMU1_LDO_MODE_NORMAL, + STPMU1_LDO_MODE_NORMAL, "NORMAL"), + STPMU1_MODE(STPMU1_LDO_MODE_BYPASS, + STPMU1_LDO_MODE_BYPASS, "BYPASS"), + STPMU1_MODE(STPMU1_LDO_MODE_SINK_SOURCE, + STPMU1_LDO_MODE_SINK_SOURCE, "SINK SOURCE"), +}; + +static int stpmu1_ldo_get_value(struct udevice *dev) +{ + int sel, ldo = dev->driver_data - 1; + + sel = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); + if (sel < 0) + return sel; + + /* ldo4 => 3,3V */ + if (ldo == STPMU1_LDO4) + return STPMU1_LDO4_UV; + + sel &= STPMU1_LDO12356_OUTPUT_MASK; + sel >>= STPMU1_LDO12356_OUTPUT_SHIFT; + + /* ldo3, sel = 31 => BUCK2/2 */ + if (ldo == STPMU1_LDO3 && sel == STPMU1_LDO3_DDR_SEL) + return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2; + + return stpmu1_output_find_uv(sel, &ldo_voltage_range[ldo]); +} + +static int stpmu1_ldo_set_value(struct udevice *dev, int uv) +{ + int sel, ldo = dev->driver_data - 1; + + /* ldo4 => not possible */ + if (ldo == STPMU1_LDO4) + return -EINVAL; + + sel = stpmu1_output_find_sel(uv, &ldo_voltage_range[ldo]); + if (sel < 0) + return sel; + + return pmic_clrsetbits(dev->parent, + STPMU1_LDOX_CTRL_REG(ldo), + STPMU1_LDO12356_OUTPUT_MASK, + sel << STPMU1_LDO12356_OUTPUT_SHIFT); +} + +static int stpmu1_ldo_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, + STPMU1_LDOX_CTRL_REG(dev->driver_data - 1)); + if (ret < 0) + return false; + + return ret & STPMU1_LDO_EN ? true : false; +} + +static int stpmu1_ldo_set_enable(struct udevice *dev, bool enable) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + int ret, uv; + + /* if regulator is already in the wanted state, nothing to do */ + if (stpmu1_ldo_get_enable(dev) == enable) + return 0; + + if (enable) { + uc_pdata = dev_get_uclass_platdata(dev); + uv = stpmu1_ldo_get_value(dev); + if ((uv < uc_pdata->min_uV) || (uv > uc_pdata->max_uV)) + stpmu1_ldo_set_value(dev, uc_pdata->min_uV); + } + + ret = pmic_clrsetbits(dev->parent, + STPMU1_LDOX_CTRL_REG(dev->driver_data - 1), + STPMU1_LDO_EN, enable ? STPMU1_LDO_EN : 0); + if (enable) + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + return ret; +} + +static int stpmu1_ldo_get_mode(struct udevice *dev) +{ + int ret, ldo = dev->driver_data - 1; + + if (ldo != STPMU1_LDO3) + return -EINVAL; + + ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); + if (ret < 0) + return ret; + + if (ret & STPMU1_LDO3_MODE) + return STPMU1_LDO_MODE_BYPASS; + + ret &= STPMU1_LDO12356_OUTPUT_MASK; + ret >>= STPMU1_LDO12356_OUTPUT_SHIFT; + + return ret == STPMU1_LDO3_DDR_SEL ? STPMU1_LDO_MODE_SINK_SOURCE : + STPMU1_LDO_MODE_NORMAL; +} + +static int stpmu1_ldo_set_mode(struct udevice *dev, int mode) +{ + int ret, ldo = dev->driver_data - 1; + + if (ldo != STPMU1_LDO3) + return -EINVAL; + + ret = pmic_reg_read(dev->parent, STPMU1_LDOX_CTRL_REG(ldo)); + if (ret < 0) + return ret; + + switch (mode) { + case STPMU1_LDO_MODE_SINK_SOURCE: + ret &= ~STPMU1_LDO12356_OUTPUT_MASK; + ret |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT; + case STPMU1_LDO_MODE_NORMAL: + ret &= ~STPMU1_LDO3_MODE; + break; + case STPMU1_LDO_MODE_BYPASS: + ret |= STPMU1_LDO3_MODE; + break; + } + + return pmic_reg_write(dev->parent, STPMU1_LDOX_CTRL_REG(ldo), ret); +} + +static int stpmu1_ldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + if (!dev->driver_data || dev->driver_data > STPMU1_MAX_LDO) + return -EINVAL; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_LDO; + if (dev->driver_data - 1 == STPMU1_LDO3) { + uc_pdata->mode = (struct dm_regulator_mode *)ldo_modes; + uc_pdata->mode_count = ARRAY_SIZE(ldo_modes); + } else { + uc_pdata->mode_count = 0; + } + + return 0; +} + +static const struct dm_regulator_ops stpmu1_ldo_ops = { + .get_value = stpmu1_ldo_get_value, + .set_value = stpmu1_ldo_set_value, + .get_enable = stpmu1_ldo_get_enable, + .set_enable = stpmu1_ldo_set_enable, + .get_mode = stpmu1_ldo_get_mode, + .set_mode = stpmu1_ldo_set_mode, +}; + +U_BOOT_DRIVER(stpmu1_ldo) = { + .name = "stpmu1_ldo", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_ldo_ops, + .probe = stpmu1_ldo_probe, +}; + +/* + * VREF DDR regulator + */ + +static int stpmu1_vref_ddr_get_value(struct udevice *dev) +{ + /* BUCK2/2 */ + return stpmu1_buck_get_uv(dev->parent, STPMU1_BUCK2) / 2; +} + +static int stpmu1_vref_ddr_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_VREF_CTRL_REG); + if (ret < 0) + return false; + + return ret & STPMU1_VREF_EN ? true : false; +} + +static int stpmu1_vref_ddr_set_enable(struct udevice *dev, bool enable) +{ + int ret; + + /* if regulator is already in the wanted state, nothing to do */ + if (stpmu1_vref_ddr_get_enable(dev) == enable) + return 0; + + ret = pmic_clrsetbits(dev->parent, STPMU1_VREF_CTRL_REG, + STPMU1_VREF_EN, enable ? STPMU1_VREF_EN : 0); + if (enable) + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + return ret; +} + +static int stpmu1_vref_ddr_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_FIXED; + uc_pdata->mode_count = 0; + + return 0; +} + +static const struct dm_regulator_ops stpmu1_vref_ddr_ops = { + .get_value = stpmu1_vref_ddr_get_value, + .get_enable = stpmu1_vref_ddr_get_enable, + .set_enable = stpmu1_vref_ddr_set_enable, +}; + +U_BOOT_DRIVER(stpmu1_vref_ddr) = { + .name = "stpmu1_vref_ddr", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_vref_ddr_ops, + .probe = stpmu1_vref_ddr_probe, +}; + +/* + * BOOST regulator + */ + +static int stpmu1_boost_get_enable(struct udevice *dev) +{ + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + if (ret < 0) + return false; + + return ret & STPMU1_USB_BOOST_EN ? true : false; +} + +static int stpmu1_boost_set_enable(struct udevice *dev, bool enable) +{ + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + if (ret < 0) + return ret; + + if (!enable && ret & STPMU1_USB_PWR_SW_EN) + return -EINVAL; + + /* if regulator is already in the wanted state, nothing to do */ + if (!!(ret & STPMU1_USB_BOOST_EN) == enable) + return 0; + + ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, + STPMU1_USB_BOOST_EN, + enable ? STPMU1_USB_BOOST_EN : 0); + if (enable) + mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS); + + return ret; +} + +static int stpmu1_boost_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_FIXED; + uc_pdata->mode_count = 0; + + return 0; +} + +static const struct dm_regulator_ops stpmu1_boost_ops = { + .get_enable = stpmu1_boost_get_enable, + .set_enable = stpmu1_boost_set_enable, +}; + +U_BOOT_DRIVER(stpmu1_boost) = { + .name = "stpmu1_boost", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_boost_ops, + .probe = stpmu1_boost_probe, +}; + +/* + * USB power switch + */ + +static int stpmu1_pwr_sw_get_enable(struct udevice *dev) +{ + uint mask = 1 << dev->driver_data; + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + if (ret < 0) + return false; + + return ret & mask ? true : false; +} + +static int stpmu1_pwr_sw_set_enable(struct udevice *dev, bool enable) +{ + uint mask = 1 << dev->driver_data; + int ret; + + ret = pmic_reg_read(dev->parent, STPMU1_USB_CTRL_REG); + if (ret < 0) + return ret; + + /* if regulator is already in the wanted state, nothing to do */ + if (!!(ret & mask) == enable) + return 0; + + /* Boost management */ + if (enable && !(ret & STPMU1_USB_BOOST_EN)) { + pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, + STPMU1_USB_BOOST_EN, STPMU1_USB_BOOST_EN); + mdelay(STPMU1_USB_BOOST_START_UP_DELAY_MS); + } else if (!enable && ret & STPMU1_USB_BOOST_EN && + (ret & STPMU1_USB_PWR_SW_EN) != STPMU1_USB_PWR_SW_EN) { + pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, + STPMU1_USB_BOOST_EN, 0); + } + + ret = pmic_clrsetbits(dev->parent, STPMU1_USB_CTRL_REG, + mask, enable ? mask : 0); + if (enable) + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + return ret; +} + +static int stpmu1_pwr_sw_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + if (!dev->driver_data || dev->driver_data > STPMU1_MAX_PWR_SW) + return -EINVAL; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_FIXED; + uc_pdata->mode_count = 0; + + return 0; +} + +static const struct dm_regulator_ops stpmu1_pwr_sw_ops = { + .get_enable = stpmu1_pwr_sw_get_enable, + .set_enable = stpmu1_pwr_sw_set_enable, +}; + +U_BOOT_DRIVER(stpmu1_pwr_sw) = { + .name = "stpmu1_pwr_sw", + .id = UCLASS_REGULATOR, + .ops = &stpmu1_pwr_sw_ops, + .probe = stpmu1_pwr_sw_probe, +}; diff --git a/include/configs/khadas-vim.h b/include/configs/khadas-vim.h index db65f71d43..3a9c1e6992 100644 --- a/include/configs/khadas-vim.h +++ b/include/configs/khadas-vim.h @@ -13,6 +13,6 @@ #define MESON_FDTFILE_SETTING "fdtfile=amlogic/meson-gxl-s905x-khadas-vim.dtb\0" -#include <configs/meson-gxbb-common.h> +#include <configs/meson-gx-common.h> #endif /* __CONFIG_H */ diff --git a/include/configs/libretech-cc.h b/include/configs/libretech-cc.h index dc778dc66a..b44d3bdd32 100644 --- a/include/configs/libretech-cc.h +++ b/include/configs/libretech-cc.h @@ -13,6 +13,6 @@ #define MESON_FDTFILE_SETTING "fdtfile=amlogic/meson-gxl-s905x-libretech-cc.dtb\0" -#include <configs/meson-gxbb-common.h> +#include <configs/meson-gx-common.h> #endif /* __CONFIG_H */ diff --git a/include/configs/meson-gxbb-common.h b/include/configs/meson-gx-common.h index 068e36e8d5..6e61b704a3 100644 --- a/include/configs/meson-gxbb-common.h +++ b/include/configs/meson-gx-common.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Configuration for Amlogic Meson GXBB SoCs + * Configuration for Amlogic Meson GX SoCs * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com> */ -#ifndef __MESON_GXBB_COMMON_CONFIG_H -#define __MESON_GXBB_COMMON_CONFIG_H +#ifndef __MESON_GX_COMMON_CONFIG_H +#define __MESON_GX_COMMON_CONFIG_H #define CONFIG_CPU_ARMV8 #define CONFIG_REMAKE_ELF @@ -43,4 +43,4 @@ #define CONFIG_SYS_BOOTM_LEN (64 << 20) /* 64 MiB */ -#endif /* __MESON_GXBB_COMMON_CONFIG_H */ +#endif /* __MESON_GX_COMMON_CONFIG_H */ diff --git a/include/configs/odroid-c2.h b/include/configs/odroid-c2.h index a8ad21edf6..913943421a 100644 --- a/include/configs/odroid-c2.h +++ b/include/configs/odroid-c2.h @@ -13,6 +13,6 @@ #define MESON_FDTFILE_SETTING "fdtfile=amlogic/meson-gxbb-odroidc2.dtb\0" -#include <configs/meson-gxbb-common.h> +#include <configs/meson-gx-common.h> #endif /* __CONFIG_H */ diff --git a/include/configs/p212.h b/include/configs/p212.h index 0e49437209..53af6bc21c 100644 --- a/include/configs/p212.h +++ b/include/configs/p212.h @@ -15,6 +15,6 @@ #define MESON_FDTFILE_SETTING "fdtfile=amlogic/meson-gxl-s905x-p212.dtb\0" -#include <configs/meson-gxbb-common.h> +#include <configs/meson-gx-common.h> #endif /* __CONFIG_H */ diff --git a/include/dt-bindings/clock/gxbb-aoclkc.h b/include/dt-bindings/clock/gxbb-aoclkc.h index 31751482d1..9d15e2221f 100644 --- a/include/dt-bindings/clock/gxbb-aoclkc.h +++ b/include/dt-bindings/clock/gxbb-aoclkc.h @@ -62,5 +62,6 @@ #define CLKID_AO_UART1 3 #define CLKID_AO_UART2 4 #define CLKID_AO_IR_BLASTER 5 +#define CLKID_AO_CEC_32K 6 #endif diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h index e3e9f7919c..8ba99a5e3f 100644 --- a/include/dt-bindings/clock/gxbb-clkc.h +++ b/include/dt-bindings/clock/gxbb-clkc.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * GXBB clock tree IDs */ @@ -5,37 +6,96 @@ #ifndef __GXBB_CLKC_H #define __GXBB_CLKC_H +#define CLKID_SYS_PLL 0 #define CLKID_HDMI_PLL 2 +#define CLKID_FIXED_PLL 3 #define CLKID_FCLK_DIV2 4 #define CLKID_FCLK_DIV3 5 #define CLKID_FCLK_DIV4 6 +#define CLKID_FCLK_DIV5 7 +#define CLKID_FCLK_DIV7 8 #define CLKID_GP0_PLL 9 #define CLKID_CLK81 12 +#define CLKID_MPLL0 13 +#define CLKID_MPLL1 14 #define CLKID_MPLL2 15 +#define CLKID_DDR 16 +#define CLKID_DOS 17 +#define CLKID_ISA 18 +#define CLKID_PL301 19 +#define CLKID_PERIPHS 20 #define CLKID_SPICC 21 #define CLKID_I2C 22 #define CLKID_SAR_ADC 23 +#define CLKID_SMART_CARD 24 #define CLKID_RNG0 25 #define CLKID_UART0 26 +#define CLKID_SDHC 27 +#define CLKID_STREAM 28 +#define CLKID_ASYNC_FIFO 29 +#define CLKID_SDIO 30 +#define CLKID_ABUF 31 +#define CLKID_HIU_IFACE 32 +#define CLKID_ASSIST_MISC 33 #define CLKID_SPI 34 #define CLKID_ETH 36 +#define CLKID_I2S_SPDIF 35 +#define CLKID_DEMUX 37 #define CLKID_AIU_GLUE 38 #define CLKID_IEC958 39 #define CLKID_I2S_OUT 40 +#define CLKID_AMCLK 41 +#define CLKID_AIFIFO2 42 +#define CLKID_MIXER 43 #define CLKID_MIXER_IFACE 44 +#define CLKID_ADC 45 +#define CLKID_BLKMV 46 #define CLKID_AIU 47 #define CLKID_UART1 48 +#define CLKID_G2D 49 #define CLKID_USB0 50 #define CLKID_USB1 51 +#define CLKID_RESET 52 +#define CLKID_NAND 53 +#define CLKID_DOS_PARSER 54 #define CLKID_USB 55 +#define CLKID_VDIN1 56 +#define CLKID_AHB_ARB0 57 +#define CLKID_EFUSE 58 +#define CLKID_BOOT_ROM 59 +#define CLKID_AHB_DATA_BUS 60 +#define CLKID_AHB_CTRL_BUS 61 +#define CLKID_HDMI_INTR_SYNC 62 #define CLKID_HDMI_PCLK 63 #define CLKID_USB1_DDR_BRIDGE 64 #define CLKID_USB0_DDR_BRIDGE 65 +#define CLKID_MMC_PCLK 66 +#define CLKID_DVIN 67 #define CLKID_UART2 68 #define CLKID_SANA 69 +#define CLKID_VPU_INTR 70 +#define CLKID_SEC_AHB_AHB3_BRIDGE 71 +#define CLKID_CLK81_A53 72 +#define CLKID_VCLK2_VENCI0 73 +#define CLKID_VCLK2_VENCI1 74 +#define CLKID_VCLK2_VENCP0 75 +#define CLKID_VCLK2_VENCP1 76 #define CLKID_GCLK_VENCI_INT0 77 +#define CLKID_GCLK_VENCI_INT 78 +#define CLKID_DAC_CLK 79 #define CLKID_AOCLK_GATE 80 #define CLKID_IEC958_GATE 81 +#define CLKID_ENC480P 82 +#define CLKID_RNG1 83 +#define CLKID_GCLK_VENCI_INT1 84 +#define CLKID_VCLK2_VENCLMCC 85 +#define CLKID_VCLK2_VENCL 86 +#define CLKID_VCLK_OTHER 87 +#define CLKID_EDP 88 +#define CLKID_AO_MEDIA_CPU 89 +#define CLKID_AO_AHB_SRAM 90 +#define CLKID_AO_AHB_BUS 91 +#define CLKID_AO_IFACE 92 #define CLKID_AO_I2C 93 #define CLKID_SD_EMMC_A 94 #define CLKID_SD_EMMC_B 95 @@ -50,5 +110,20 @@ #define CLKID_CTS_AMCLK 107 #define CLKID_CTS_MCLK_I958 110 #define CLKID_CTS_I958 113 +#define CLKID_32K_CLK 114 +#define CLKID_SD_EMMC_A_CLK0 119 +#define CLKID_SD_EMMC_B_CLK0 122 +#define CLKID_SD_EMMC_C_CLK0 125 +#define CLKID_VPU_0_SEL 126 +#define CLKID_VPU_0 128 +#define CLKID_VPU_1_SEL 129 +#define CLKID_VPU_1 131 +#define CLKID_VPU 132 +#define CLKID_VAPB_0_SEL 133 +#define CLKID_VAPB_0 135 +#define CLKID_VAPB_1_SEL 136 +#define CLKID_VAPB_1 138 +#define CLKID_VAPB_SEL 139 +#define CLKID_VAPB 140 #endif /* __GXBB_CLKC_H */ diff --git a/include/dt-bindings/gpio/meson-gxbb-gpio.h b/include/dt-bindings/gpio/meson-gxbb-gpio.h index 58654fd7aa..43a68a1110 100644 --- a/include/dt-bindings/gpio/meson-gxbb-gpio.h +++ b/include/dt-bindings/gpio/meson-gxbb-gpio.h @@ -29,6 +29,7 @@ #define GPIOAO_11 11 #define GPIOAO_12 12 #define GPIOAO_13 13 +#define GPIO_TEST_N 14 #define GPIOZ_0 0 #define GPIOZ_1 1 @@ -149,6 +150,5 @@ #define GPIOCLK_1 116 #define GPIOCLK_2 117 #define GPIOCLK_3 118 -#define GPIO_TEST_N 119 #endif diff --git a/include/dt-bindings/gpio/meson-gxl-gpio.h b/include/dt-bindings/gpio/meson-gxl-gpio.h index 684d0d7add..01f2a2abd3 100644 --- a/include/dt-bindings/gpio/meson-gxl-gpio.h +++ b/include/dt-bindings/gpio/meson-gxl-gpio.h @@ -25,6 +25,7 @@ #define GPIOAO_7 7 #define GPIOAO_8 8 #define GPIOAO_9 9 +#define GPIO_TEST_N 10 #define GPIOZ_0 0 #define GPIOZ_1 1 @@ -126,6 +127,5 @@ #define GPIOX_18 97 #define GPIOCLK_0 98 #define GPIOCLK_1 99 -#define GPIO_TEST_N 100 #endif diff --git a/include/dt-bindings/mfd/st,stpmu1.h b/include/dt-bindings/mfd/st,stpmu1.h new file mode 100644 index 0000000000..81982ebe2c --- /dev/null +++ b/include/dt-bindings/mfd/st,stpmu1.h @@ -0,0 +1,60 @@ +/* + * This file is part of stpmu1 pmic driver + * + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics. + * + * License type: GPLv2 + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __DT_BINDINGS_STPMU1_H__ +#define __DT_BINDINGS_STPMU1_H__ + +/* IRQ definitions */ +#define IT_PONKEY_F 0 +#define IT_PONKEY_R 1 +#define IT_WAKEUP_F 2 +#define IT_WAKEUP_R 3 +#define IT_VBUS_OTG_F 4 +#define IT_VBUS_OTG_R 5 +#define IT_SWOUT_F 6 +#define IT_SWOUT_R 7 + +#define IT_CURLIM_BUCK1 8 +#define IT_CURLIM_BUCK2 9 +#define IT_CURLIM_BUCK3 10 +#define IT_CURLIM_BUCK4 11 +#define IT_OCP_OTG 12 +#define IT_OCP_SWOUT 13 +#define IT_OCP_BOOST 14 +#define IT_OVP_BOOST 15 + +#define IT_CURLIM_LDO1 16 +#define IT_CURLIM_LDO2 17 +#define IT_CURLIM_LDO3 18 +#define IT_CURLIM_LDO4 19 +#define IT_CURLIM_LDO5 20 +#define IT_CURLIM_LDO6 21 +#define IT_SHORT_SWOTG 22 +#define IT_SHORT_SWOUT 23 + +#define IT_TWARN_F 24 +#define IT_TWARN_R 25 +#define IT_VINLOW_F 26 +#define IT_VINLOW_R 27 +#define IT_SWIN_F 30 +#define IT_SWIN_R 31 + +#endif /* __DT_BINDINGS_STPMU1_H__ */ diff --git a/include/environment/ti/boot.h b/include/environment/ti/boot.h index 31042fad67..a0e1cd1656 100644 --- a/include/environment/ti/boot.h +++ b/include/environment/ti/boot.h @@ -36,6 +36,7 @@ "run mmcboot;\0" \ "emmc_android_boot=" \ "echo Trying to boot Android from eMMC ...; " \ + "run update_to_fit; " \ "setenv eval_bootargs setenv bootargs $bootargs; " \ "run eval_bootargs; " \ "setenv mmcdev 1; " \ @@ -48,7 +49,7 @@ "part size mmc ${mmcdev} boot boot_size; " \ "mmc read ${fdtaddr} ${fdt_start} ${fdt_size}; " \ "mmc read ${loadaddr} ${boot_start} ${boot_size}; " \ - "bootm $loadaddr $loadaddr $fdtaddr;\0" + "bootm ${loadaddr}#${fdtfile};\0 " #ifdef CONFIG_OMAP54XX diff --git a/include/image-sparse.h b/include/image-sparse.h index 4d1f910487..f39dc16617 100644 --- a/include/image-sparse.h +++ b/include/image-sparse.h @@ -22,6 +22,8 @@ struct sparse_storage { lbaint_t (*reserve)(struct sparse_storage *info, lbaint_t blk, lbaint_t blkcnt); + + void (*mssg)(const char *str); }; static inline int is_sparse_image(void *buf) @@ -35,5 +37,5 @@ static inline int is_sparse_image(void *buf) return 0; } -void write_sparse_image(struct sparse_storage *info, const char *part_name, - void *data, unsigned sz); +int write_sparse_image(struct sparse_storage *info, const char *part_name, + void *data); diff --git a/include/regmap.h b/include/regmap.h index e96c79dd26..6a574eaa41 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -43,6 +43,16 @@ int regmap_read(struct regmap *map, uint offset, uint *valp); regmap_read(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), valp) /** + * regmap_update_bits() - Perform a read/modify/write using a mask + * + * @map: The map returned by regmap_init_mem*() + * @offset: Offset of the memory + * @mask: Mask to apply to the read value + * @val: Value to apply to the value to write + */ +int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val); + +/** * regmap_init_mem() - Set up a new register map that uses memory access * * Use regmap_uninit() to free it. diff --git a/include/stm32_rcc.h b/include/stm32_rcc.h index 748c2ebd0c..71da3c1a87 100644 --- a/include/stm32_rcc.h +++ b/include/stm32_rcc.h @@ -40,7 +40,8 @@ struct stm32_clk_info { }; enum soc_family { - STM32F4, + STM32F42X, + STM32F469, STM32F7, }; diff --git a/lib/Kconfig b/lib/Kconfig index 33fb06712f..1590f7afa4 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -286,6 +286,8 @@ config OF_LIBFDT config OF_LIBFDT_OVERLAY bool "Enable the FDT library overlay support" + depends on OF_LIBFDT + default y if ARCH_OMAP2PLUS || ARCH_KEYSTONE help This enables the FDT library (libfdt) overlay support. diff --git a/test/dm/led.c b/test/dm/led.c index 89c0c95855..0071f216bb 100644 --- a/test/dm/led.c +++ b/test/dm/led.c @@ -19,12 +19,30 @@ static int dm_test_led_base(struct unit_test_state *uts) ut_assertok(uclass_get_device(UCLASS_LED, 0, &dev)); ut_assertok(uclass_get_device(UCLASS_LED, 1, &dev)); ut_assertok(uclass_get_device(UCLASS_LED, 2, &dev)); - ut_asserteq(-ENODEV, uclass_get_device(UCLASS_LED, 3, &dev)); + ut_assertok(uclass_get_device(UCLASS_LED, 3, &dev)); + ut_assertok(uclass_get_device(UCLASS_LED, 4, &dev)); + ut_asserteq(-ENODEV, uclass_get_device(UCLASS_LED, 5, &dev)); return 0; } DM_TEST(dm_test_led_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +/* Test of the LED 'default-state' device tree property */ +static int dm_test_led_default_state(struct unit_test_state *uts) +{ + struct udevice *dev; + + /* Check that we handle the default-state property correctly. */ + ut_assertok(led_get_by_label("sandbox:default_on", &dev)); + ut_asserteq(LEDST_ON, led_get_state(dev)); + + ut_assertok(led_get_by_label("sandbox:default_off", &dev)); + ut_asserteq(LEDST_OFF, led_get_state(dev)); + + return 0; +} +DM_TEST(dm_test_led_default_state, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + /* Test of the led uclass using the led_gpio driver */ static int dm_test_led_gpio(struct unit_test_state *uts) { diff --git a/test/dm/regmap.c b/test/dm/regmap.c index 5b51a90488..d4b86b3b03 100644 --- a/test/dm/regmap.c +++ b/test/dm/regmap.c @@ -91,3 +91,28 @@ static int dm_test_regmap_syscon(struct unit_test_state *uts) } DM_TEST(dm_test_regmap_syscon, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Read/Write/Modify test */ +static int dm_test_regmap_rw(struct unit_test_state *uts) +{ + struct udevice *dev; + struct regmap *map; + uint reg; + + ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev)); + map = syscon_get_regmap(dev); + ut_assertok_ptr(map); + + ut_assertok(regmap_write(map, 0, 0xcacafafa)); + ut_assertok(regmap_write(map, 3, 0x55aa2211)); + + ut_assertok(regmap_read(map, 0, ®)); + ut_assertok(regmap_read(map, 3, ®)); + + ut_assertok(regmap_update_bits(map, 0, 0xff00ff00, 0x55aa2211)); + ut_assertok(regmap_update_bits(map, 3, 0x00ff00ff, 0xcacafada)); + + return 0; +} + +DM_TEST(dm_test_regmap_rw, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); |