CI: https://source.denx.de/u-boot/custodians/u-boot-imx/-/pipelines/25652

- Add i.MX8MP LDB support.
- Various phycore-imx93 environment improvements.
- Add support for Toradex SMARC iMX8MP.
This commit is contained in:
Tom Rini
2025-04-11 09:11:38 -06:00
47 changed files with 5678 additions and 95 deletions

View File

@@ -0,0 +1,80 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/* Copyright (C) 2024 Toradex */
#include "imx8mp-u-boot.dtsi"
/ {
sysinfo {
compatible = "toradex,sysinfo";
};
};
&gpio1 {
bootph-pre-ram;
};
&gpio2 {
bt_uart_gpio {
gpio-hog;
gpios = <9 GPIO_ACTIVE_HIGH>;
input;
line-name = "BT_UART_RXD_GPIO";
};
};
&gpio3 {
wifi_en_gpio {
gpio-hog;
gpios = <14 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "CTRL_EN_WIFI";
};
};
&gpio5 {
bootph-pre-ram;
};
&i2c1 {
bootph-pre-ram;
};
&pca9450 {
bootph-pre-ram;
regulators {
bootph-pre-ram;
};
};
&pinctrl_i2c1 {
bootph-pre-ram;
};
&pinctrl_i2c1_gpio {
bootph-pre-ram;
};
&pinctrl_pmic {
bootph-pre-ram;
};
&pinctrl_uart4 {
bootph-pre-ram;
};
&uart3 {
status = "disabled";
};
&uart4 {
bootph-pre-ram;
};
&usdhc1 {
status = "disabled";
};
&usdhc3 {
bootph-pre-ram;
};

View File

@@ -0,0 +1,297 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/* Copyright (C) 2025 Toradex */
/dts-v1/;
#include "imx8mp-toradex-smarc.dtsi"
/ {
model = "Toradex SMARC iMX8M Plus on Toradex SMARC Development Board";
compatible = "toradex,smarc-imx8mp-dev",
"toradex,smarc-imx8mp",
"fsl,imx8mp";
hdmi-connector {
compatible = "hdmi-connector";
label = "J64";
type = "a";
port {
native_hdmi_connector_in: endpoint {
remote-endpoint = <&hdmi_tx_out>;
};
};
};
reg_carrier_1p8v: regulator-carrier-1p8v {
compatible = "regulator-fixed";
regulator-max-microvolt = <1800000>;
regulator-min-microvolt = <1800000>;
regulator-name = "On-carrier 1V8";
};
sound {
compatible = "simple-audio-card";
simple-audio-card,bitclock-master = <&codec_dai>;
simple-audio-card,format = "i2s";
simple-audio-card,frame-master = <&codec_dai>;
simple-audio-card,mclk-fs = <256>;
simple-audio-card,name = "tdx-smarc-wm8904";
simple-audio-card,routing =
"Headphone Jack", "HPOUTL",
"Headphone Jack", "HPOUTR",
"IN2L", "Line In Jack",
"IN2R", "Line In Jack",
"Microphone Jack", "MICBIAS",
"IN1L", "Microphone Jack";
simple-audio-card,widgets =
"Microphone", "Microphone Jack",
"Headphone", "Headphone Jack",
"Line", "Line In Jack";
codec_dai: simple-audio-card,codec {
clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1>;
sound-dai = <&wm8904_1a>;
};
simple-audio-card,cpu {
sound-dai = <&sai1>;
};
};
};
&aud2htx {
status = "okay";
};
/* SMARC SPI0 */
&ecspi1 {
status = "okay";
};
/* SMARC GBE0 */
&eqos {
status = "okay";
};
/* SMARC GBE1 */
&fec {
status = "okay";
};
/* SMARC CAN1 */
&flexcan1 {
status = "okay";
};
/* SMARC CAN0 */
&flexcan2 {
status = "okay";
};
&gpio1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio7>,
<&pinctrl_gpio8>,
<&pinctrl_gpio9>,
<&pinctrl_gpio10>,
<&pinctrl_gpio11>,
<&pinctrl_gpio12>,
<&pinctrl_gpio13>;
};
&gpio3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lvds_dsi_sel>;
};
&gpio4 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio4>, <&pinctrl_gpio6>;
};
&hdmi_pvi {
status = "okay";
};
/* SMARC HDMI */
&hdmi_tx {
status = "okay";
ports {
port@1 {
hdmi_tx_out: endpoint {
remote-endpoint = <&native_hdmi_connector_in>;
};
};
};
};
&hdmi_tx_phy {
status = "okay";
};
/* SMARC I2C_LCD */
&i2c2 {
status = "okay";
i2c-mux@70 {
compatible = "nxp,pca9543";
reg = <0x70>;
#address-cells = <1>;
#size-cells = <0>;
/* I2C on DSI Connector Pins 4/6 */
i2c_dsi_0: i2c@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
};
/* I2C on DSI Connector Pins 52/54 */
i2c_dsi_1: i2c@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
};
};
};
/* SMARC I2C_CAM0 */
&i2c3 {
status = "okay";
};
/* SMARC I2C_GP */
&i2c4 {
/* Audio Codec */
wm8904_1a: audio-codec@1a {
compatible = "wlf,wm8904";
reg = <0x1a>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sai1>, <&pinctrl_sai1_mclk>;
#sound-dai-cells = <0>;
clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SAI1_MCLK1>;
clock-names = "mclk";
AVDD-supply = <&reg_carrier_1p8v>;
CPVDD-supply = <&reg_carrier_1p8v>;
DBVDD-supply = <&reg_carrier_1p8v>;
DCVDD-supply = <&reg_carrier_1p8v>;
MICVDD-supply = <&reg_carrier_1p8v>;
};
/* On-Carrier Temperature Sensor */
temperature-sensor@4f {
compatible = "ti,tmp1075";
reg = <0x4f>;
};
/* On-Carrier EEPROM */
eeprom@57 {
compatible = "st,24c02", "atmel,24c02";
reg = <0x57>;
pagesize = <16>;
};
};
/* SMARC I2C_CAM1 */
&i2c5 {
status = "okay";
};
/* SMARC I2C_PM */
&i2c6 {
clock-frequency = <100000>;
status = "okay";
/* Fan controller */
fan@18 {
compatible = "ti,amc6821";
reg = <0x18>;
};
/* Current measurement into module VDD */
hwmon@40 {
compatible = "ti,ina226";
reg = <0x40>;
shunt-resistor = <5000>;
};
};
&lcdif3 {
status = "okay";
};
/* SMARC PCIE_A, M2 Key B */
&pcie {
status = "okay";
};
&pcie_phy {
status = "okay";
};
/* SMARC LCD1_BKLT_PWM */
&pwm1 {
status = "okay";
};
/* SMARC LCD0_BKLT_PWM */
&pwm2 {
status = "okay";
};
/* SMARC I2S0 */
&sai1 {
assigned-clocks = <&clk IMX8MP_CLK_SAI1>;
assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
assigned-clock-rates = <24576000>;
fsl,sai-mclk-direction-output;
status = "okay";
};
/* SMARC HDMI Audio */
&sound_hdmi {
status = "okay";
};
/* SMARC SER0, RS485. Optional M.2 KEY E */
&uart1 {
linux,rs485-enabled-at-boot-time;
rs485-rts-active-low;
rs485-rx-during-tx;
status = "okay";
};
/* SMARC SER2 */
&uart2 {
status = "okay";
};
/* SMARC SER1, used as the Linux Console */
&uart4 {
status = "okay";
};
/* SMARC USB0 */
&usb3_0 {
status = "okay";
};
/* SMARC USB1..4 */
&usb3_1 {
status = "okay";
};
&usb3_phy0 {
status = "okay";
};
&usb3_phy1 {
status = "okay";
};
/* SMARC SDIO */
&usdhc2 {
status = "okay";
};

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,20 @@
#address-cells = <1>;
#size-cells = <0>;
idle-states {
entry-method = "psci";
cpu_pd_wait: cpu-pd-wait {
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x0010033>;
local-timer-stop;
entry-latency-us = <1000>;
exit-latency-us = <700>;
min-residency-us = <2700>;
wakeup-latency-us = <1500>;
};
};
A53_0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53";
@@ -65,6 +79,7 @@
nvmem-cell-names = "speed_grade";
operating-points-v2 = <&a53_opp_table>;
#cooling-cells = <2>;
cpu-idle-states = <&cpu_pd_wait>;
};
A53_1: cpu@1 {
@@ -83,6 +98,7 @@
next-level-cache = <&A53_L2>;
operating-points-v2 = <&a53_opp_table>;
#cooling-cells = <2>;
cpu-idle-states = <&cpu_pd_wait>;
};
A53_2: cpu@2 {
@@ -101,6 +117,7 @@
next-level-cache = <&A53_L2>;
operating-points-v2 = <&a53_opp_table>;
#cooling-cells = <2>;
cpu-idle-states = <&cpu_pd_wait>;
};
A53_3: cpu@3 {
@@ -119,6 +136,7 @@
next-level-cache = <&A53_L2>;
operating-points-v2 = <&a53_opp_table>;
#cooling-cells = <2>;
cpu-idle-states = <&cpu_pd_wait>;
};
A53_L2: l2-cache0 {
@@ -264,6 +282,7 @@
dsp_reserved: dsp@92400000 {
reg = <0 0x92400000 0 0x2000000>;
no-map;
status = "disabled";
};
};
@@ -726,6 +745,8 @@
clk: clock-controller@30380000 {
compatible = "fsl,imx8mp-ccm";
reg = <0x30380000 0x10000>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
#clock-cells = <1>;
clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>,
<&clk_ext3>, <&clk_ext4>;
@@ -786,6 +807,23 @@
reg = <IMX8MP_POWER_DOMAIN_USB2_PHY>;
};
pgc_mlmix: power-domain@4 {
#power-domain-cells = <0>;
reg = <IMX8MP_POWER_DOMAIN_MLMIX>;
clocks = <&clk IMX8MP_CLK_ML_AXI>,
<&clk IMX8MP_CLK_ML_AHB>,
<&clk IMX8MP_CLK_NPU_ROOT>;
assigned-clocks = <&clk IMX8MP_CLK_ML_CORE>,
<&clk IMX8MP_CLK_ML_AXI>,
<&clk IMX8MP_CLK_ML_AHB>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>,
<&clk IMX8MP_SYS_PLL1_800M>,
<&clk IMX8MP_SYS_PLL1_800M>;
assigned-clock-rates = <1000000000>,
<800000000>,
<400000000>;
};
pgc_audio: power-domain@5 {
#power-domain-cells = <0>;
reg = <IMX8MP_POWER_DOMAIN_AUDIOMIX>;
@@ -793,10 +831,10 @@
<&clk IMX8MP_CLK_AUDIO_AXI>;
assigned-clocks = <&clk IMX8MP_CLK_AUDIO_AHB>,
<&clk IMX8MP_CLK_AUDIO_AXI_SRC>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>,
<&clk IMX8MP_SYS_PLL1_800M>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>,
<&clk IMX8MP_SYS_PLL1_800M>;
assigned-clock-rates = <400000000>,
<600000000>;
<800000000>;
};
pgc_gpu2d: power-domain@6 {
@@ -818,6 +856,12 @@
assigned-clock-rates = <800000000>, <400000000>;
};
pgc_vpumix: power-domain@8 {
#power-domain-cells = <0>;
reg = <IMX8MP_POWER_DOMAIN_VPUMIX>;
clocks = <&clk IMX8MP_CLK_VPU_ROOT>;
};
pgc_gpu3d: power-domain@9 {
#power-domain-cells = <0>;
reg = <IMX8MP_POWER_DOMAIN_GPU3D>;
@@ -833,6 +877,45 @@
<&clk IMX8MP_CLK_MEDIA_APB_ROOT>;
};
pgc_vpu_g1: power-domain@11 {
#power-domain-cells = <0>;
power-domains = <&pgc_vpumix>;
reg = <IMX8MP_POWER_DOMAIN_VPU_G1>;
clocks = <&clk IMX8MP_CLK_VPU_G1_ROOT>;
};
pgc_vpu_g2: power-domain@12 {
#power-domain-cells = <0>;
power-domains = <&pgc_vpumix>;
reg = <IMX8MP_POWER_DOMAIN_VPU_G2>;
clocks = <&clk IMX8MP_CLK_VPU_G2_ROOT>;
};
pgc_vpu_vc8000e: power-domain@13 {
#power-domain-cells = <0>;
power-domains = <&pgc_vpumix>;
reg = <IMX8MP_POWER_DOMAIN_VPU_VC8000E>;
clocks = <&clk IMX8MP_CLK_VPU_VC8KE_ROOT>;
};
pgc_hdmimix: power-domain@14 {
#power-domain-cells = <0>;
reg = <IMX8MP_POWER_DOMAIN_HDMIMIX>;
clocks = <&clk IMX8MP_CLK_HDMI_ROOT>,
<&clk IMX8MP_CLK_HDMI_APB>;
assigned-clocks = <&clk IMX8MP_CLK_HDMI_AXI>,
<&clk IMX8MP_CLK_HDMI_APB>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_500M>,
<&clk IMX8MP_SYS_PLL1_133M>;
assigned-clock-rates = <500000000>, <133000000>;
};
pgc_hdmi_phy: power-domain@15 {
#power-domain-cells = <0>;
reg = <IMX8MP_POWER_DOMAIN_HDMI_PHY>;
};
pgc_mipi_phy2: power-domain@16 {
#power-domain-cells = <0>;
reg = <IMX8MP_POWER_DOMAIN_MIPI_PHY2>;
@@ -853,41 +936,6 @@
reg = <IMX8MP_POWER_DOMAIN_MEDIAMIX_ISPDWP>;
clocks = <&clk IMX8MP_CLK_MEDIA_ISP_ROOT>;
};
pgc_vpumix: power-domain@19 {
#power-domain-cells = <0>;
reg = <IMX8MP_POWER_DOMAIN_VPUMIX>;
clocks = <&clk IMX8MP_CLK_VPU_ROOT>;
};
pgc_vpu_g1: power-domain@20 {
#power-domain-cells = <0>;
power-domains = <&pgc_vpumix>;
reg = <IMX8MP_POWER_DOMAIN_VPU_G1>;
clocks = <&clk IMX8MP_CLK_VPU_G1_ROOT>;
};
pgc_vpu_g2: power-domain@21 {
#power-domain-cells = <0>;
power-domains = <&pgc_vpumix>;
reg = <IMX8MP_POWER_DOMAIN_VPU_G2>;
clocks = <&clk IMX8MP_CLK_VPU_G2_ROOT>;
};
pgc_vpu_vc8000e: power-domain@22 {
#power-domain-cells = <0>;
power-domains = <&pgc_vpumix>;
reg = <IMX8MP_POWER_DOMAIN_VPU_VC8000E>;
clocks = <&clk IMX8MP_CLK_VPU_VC8KE_ROOT>;
};
pgc_mlmix: power-domain@24 {
#power-domain-cells = <0>;
reg = <IMX8MP_POWER_DOMAIN_MLMIX>;
clocks = <&clk IMX8MP_CLK_ML_AXI>,
<&clk IMX8MP_CLK_ML_AHB>,
<&clk IMX8MP_CLK_NPU_ROOT>;
};
};
};
};
@@ -1231,7 +1279,7 @@
compatible = "fsl,imx8mp-usdhc", "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
reg = <0x30b40000 0x10000>;
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_DUMMY>,
clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
<&clk IMX8MP_CLK_NAND_USDHC_BUS>,
<&clk IMX8MP_CLK_USDHC1_ROOT>;
clock-names = "ipg", "ahb", "per";
@@ -1245,7 +1293,7 @@
compatible = "fsl,imx8mp-usdhc", "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
reg = <0x30b50000 0x10000>;
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_DUMMY>,
clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
<&clk IMX8MP_CLK_NAND_USDHC_BUS>,
<&clk IMX8MP_CLK_USDHC2_ROOT>;
clock-names = "ipg", "ahb", "per";
@@ -1259,7 +1307,7 @@
compatible = "fsl,imx8mp-usdhc", "fsl,imx8mm-usdhc", "fsl,imx7d-usdhc";
reg = <0x30b60000 0x10000>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_DUMMY>,
clocks = <&clk IMX8MP_CLK_IPG_ROOT>,
<&clk IMX8MP_CLK_NAND_USDHC_BUS>,
<&clk IMX8MP_CLK_USDHC3_ROOT>;
clock-names = "ipg", "ahb", "per";
@@ -1501,6 +1549,41 @@
status = "disabled";
};
aud2htx: aud2htx@30cb0000 {
compatible = "fsl,imx8mp-aud2htx";
reg = <0x30cb0000 0x10000>;
interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_AUD2HTX_IPG>;
clock-names = "bus";
dmas = <&sdma2 26 2 0>;
dma-names = "tx";
status = "disabled";
};
xcvr: xcvr@30cc0000 {
compatible = "fsl,imx8mp-xcvr";
reg = <0x30cc0000 0x800>,
<0x30cc0800 0x400>,
<0x30cc0c00 0x080>,
<0x30cc0e00 0x080>;
reg-names = "ram", "regs", "rxfifo",
"txfifo";
interrupts = /* XCVR IRQ 0 */
<GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
/* XCVR IRQ 1 */
<GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
/* XCVR PHY - SPDIF wakeup IRQ */
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_EARC_IPG>,
<&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_EARC_PHY>,
<&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_SPBA2_ROOT>,
<&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_AUDPLL_ROOT>;
clock-names = "ipg", "phy", "spba", "pll_ipg";
dmas = <&sdma2 30 2 0>, <&sdma2 31 2 0>;
dma-names = "rx", "tx";
resets = <&audio_blk_ctrl 0>;
status = "disabled";
};
};
sdma3: dma-controller@30e00000 {
@@ -1529,17 +1612,22 @@
compatible = "fsl,imx8mp-audio-blk-ctrl";
reg = <0x30e20000 0x10000>;
#clock-cells = <1>;
#reset-cells = <1>;
clocks = <&clk IMX8MP_CLK_AUDIO_ROOT>,
<&clk IMX8MP_CLK_SAI1>,
<&clk IMX8MP_CLK_SAI2>,
<&clk IMX8MP_CLK_SAI3>,
<&clk IMX8MP_CLK_SAI5>,
<&clk IMX8MP_CLK_SAI6>,
<&clk IMX8MP_CLK_SAI7>;
<&clk IMX8MP_CLK_SAI7>,
<&clk IMX8MP_CLK_AUDIO_AXI_ROOT>;
clock-names = "ahb",
"sai1", "sai2", "sai3",
"sai5", "sai6", "sai7";
"sai5", "sai6", "sai7", "axi";
power-domains = <&pgc_audio>;
assigned-clocks = <&clk IMX8MP_AUDIO_PLL1>,
<&clk IMX8MP_AUDIO_PLL2>;
assigned-clock-rates = <393216000>, <361267200>;
};
};
@@ -1604,6 +1692,50 @@
};
};
isp_0: isp@32e10000 {
compatible = "fsl,imx8mp-isp";
reg = <0x32e10000 0x10000>;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_MEDIA_ISP_ROOT>,
<&clk IMX8MP_CLK_MEDIA_AXI_ROOT>,
<&clk IMX8MP_CLK_MEDIA_APB_ROOT>;
clock-names = "isp", "aclk", "hclk";
power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_ISP>;
fsl,blk-ctrl = <&media_blk_ctrl 0>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@1 {
reg = <1>;
};
};
};
isp_1: isp@32e20000 {
compatible = "fsl,imx8mp-isp";
reg = <0x32e20000 0x10000>;
interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_MEDIA_ISP_ROOT>,
<&clk IMX8MP_CLK_MEDIA_AXI_ROOT>,
<&clk IMX8MP_CLK_MEDIA_APB_ROOT>;
clock-names = "isp", "aclk", "hclk";
power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_ISP>;
fsl,blk-ctrl = <&media_blk_ctrl 1>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@1 {
reg = <1>;
};
};
};
dewarp: dwe@32e30000 {
compatible = "nxp,imx8mp-dw100";
reg = <0x32e30000 0x10000>;
@@ -1618,15 +1750,16 @@
compatible = "fsl,imx8mp-mipi-csi2", "fsl,imx8mm-mipi-csi2";
reg = <0x32e40000 0x10000>;
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <500000000>;
clock-frequency = <250000000>;
clocks = <&clk IMX8MP_CLK_MEDIA_APB_ROOT>,
<&clk IMX8MP_CLK_MEDIA_CAM1_PIX_ROOT>,
<&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF_ROOT>,
<&clk IMX8MP_CLK_MEDIA_AXI_ROOT>;
clock-names = "pclk", "wrap", "phy", "axi";
assigned-clocks = <&clk IMX8MP_CLK_MEDIA_CAM1_PIX>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>;
assigned-clock-rates = <500000000>;
assigned-clocks = <&clk IMX8MP_CLK_MEDIA_CAM1_PIX>,
<&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_250M>,
<&clk IMX8MP_CLK_24M>;
power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_MIPI_CSI2_1>;
status = "disabled";
@@ -1652,15 +1785,16 @@
compatible = "fsl,imx8mp-mipi-csi2", "fsl,imx8mm-mipi-csi2";
reg = <0x32e50000 0x10000>;
interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <266000000>;
clock-frequency = <250000000>;
clocks = <&clk IMX8MP_CLK_MEDIA_APB_ROOT>,
<&clk IMX8MP_CLK_MEDIA_CAM2_PIX_ROOT>,
<&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF_ROOT>,
<&clk IMX8MP_CLK_MEDIA_AXI_ROOT>;
clock-names = "pclk", "wrap", "phy", "axi";
assigned-clocks = <&clk IMX8MP_CLK_MEDIA_CAM2_PIX>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>;
assigned-clock-rates = <266000000>;
assigned-clocks = <&clk IMX8MP_CLK_MEDIA_CAM2_PIX>,
<&clk IMX8MP_CLK_MEDIA_MIPI_PHY1_REF>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_250M>,
<&clk IMX8MP_CLK_24M>;
power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_MIPI_CSI2_2>;
status = "disabled";
@@ -1709,6 +1843,13 @@
remote-endpoint = <&lcdif1_to_dsim>;
};
};
port@1 {
reg = <1>;
mipi_dsi_out: endpoint {
};
};
};
};
@@ -1791,24 +1932,33 @@
clock-names = "apb", "axi", "cam1", "cam2",
"disp1", "disp2", "isp", "phy";
/*
* The ISP maximum frequency is 400MHz in normal mode
* and 500MHz in overdrive mode. The 400MHz operating
* point hasn't been successfully tested yet, so set
* IMX8MP_CLK_MEDIA_ISP to 500MHz for the time being.
*/
assigned-clocks = <&clk IMX8MP_CLK_MEDIA_AXI>,
<&clk IMX8MP_CLK_MEDIA_APB>,
<&clk IMX8MP_CLK_MEDIA_DISP1_PIX>,
<&clk IMX8MP_CLK_MEDIA_DISP2_PIX>,
<&clk IMX8MP_CLK_MEDIA_ISP>,
<&clk IMX8MP_VIDEO_PLL1>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>,
<&clk IMX8MP_SYS_PLL1_800M>,
<&clk IMX8MP_VIDEO_PLL1_OUT>,
<&clk IMX8MP_VIDEO_PLL1_OUT>;
<&clk IMX8MP_VIDEO_PLL1_OUT>,
<&clk IMX8MP_SYS_PLL2_500M>;
assigned-clock-rates = <500000000>, <200000000>,
<0>, <0>, <1039500000>;
<0>, <0>, <500000000>,
<1039500000>;
#power-domain-cells = <1>;
lvds_bridge: bridge@5c {
compatible = "fsl,imx8mp-ldb";
reg = <0x5c 0x4>, <0x128 0x4>;
reg-names = "ldb", "lvds";
clocks = <&clk IMX8MP_CLK_MEDIA_LDB>;
clocks = <&clk IMX8MP_CLK_MEDIA_LDB_ROOT>;
clock-names = "ldb";
assigned-clocks = <&clk IMX8MP_CLK_MEDIA_LDB>;
assigned-clock-parents = <&clk IMX8MP_VIDEO_PLL1_OUT>;
@@ -1873,6 +2023,136 @@
#power-domain-cells = <1>;
#clock-cells = <0>;
};
hdmi_blk_ctrl: blk-ctrl@32fc0000 {
compatible = "fsl,imx8mp-hdmi-blk-ctrl", "syscon";
reg = <0x32fc0000 0x1000>;
clocks = <&clk IMX8MP_CLK_HDMI_APB>,
<&clk IMX8MP_CLK_HDMI_ROOT>,
<&clk IMX8MP_CLK_HDMI_REF_266M>,
<&clk IMX8MP_CLK_HDMI_24M>,
<&clk IMX8MP_CLK_HDMI_FDCC_TST>;
clock-names = "apb", "axi", "ref_266m", "ref_24m", "fdcc";
power-domains = <&pgc_hdmimix>, <&pgc_hdmimix>,
<&pgc_hdmimix>, <&pgc_hdmimix>,
<&pgc_hdmimix>, <&pgc_hdmimix>,
<&pgc_hdmimix>, <&pgc_hdmi_phy>,
<&pgc_hdmimix>, <&pgc_hdmimix>;
power-domain-names = "bus", "irqsteer", "lcdif",
"pai", "pvi", "trng",
"hdmi-tx", "hdmi-tx-phy",
"hdcp", "hrv";
#power-domain-cells = <1>;
};
irqsteer_hdmi: interrupt-controller@32fc2000 {
compatible = "fsl,imx8mp-irqsteer", "fsl,imx-irqsteer";
reg = <0x32fc2000 0x1000>;
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <1>;
fsl,channel = <1>;
fsl,num-irqs = <64>;
clocks = <&clk IMX8MP_CLK_HDMI_APB>;
clock-names = "ipg";
power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_IRQSTEER>;
};
hdmi_pvi: display-bridge@32fc4000 {
compatible = "fsl,imx8mp-hdmi-pvi";
reg = <0x32fc4000 0x1000>;
interrupt-parent = <&irqsteer_hdmi>;
interrupts = <12>;
power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_PVI>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
pvi_from_lcdif3: endpoint {
remote-endpoint = <&lcdif3_to_pvi>;
};
};
port@1 {
reg = <1>;
pvi_to_hdmi_tx: endpoint {
remote-endpoint = <&hdmi_tx_from_pvi>;
};
};
};
};
lcdif3: display-controller@32fc6000 {
compatible = "fsl,imx8mp-lcdif";
reg = <0x32fc6000 0x1000>;
interrupt-parent = <&irqsteer_hdmi>;
interrupts = <8>;
clocks = <&hdmi_tx_phy>,
<&clk IMX8MP_CLK_HDMI_APB>,
<&clk IMX8MP_CLK_HDMI_ROOT>;
clock-names = "pix", "axi", "disp_axi";
power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_LCDIF>;
status = "disabled";
port {
lcdif3_to_pvi: endpoint {
remote-endpoint = <&pvi_from_lcdif3>;
};
};
};
hdmi_tx: hdmi@32fd8000 {
compatible = "fsl,imx8mp-hdmi-tx";
reg = <0x32fd8000 0x7eff>;
interrupt-parent = <&irqsteer_hdmi>;
interrupts = <0>;
clocks = <&clk IMX8MP_CLK_HDMI_APB>,
<&clk IMX8MP_CLK_HDMI_REF_266M>,
<&clk IMX8MP_CLK_32K>,
<&hdmi_tx_phy>;
clock-names = "iahb", "isfr", "cec", "pix";
assigned-clocks = <&clk IMX8MP_CLK_HDMI_REF_266M>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_266M>;
power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_HDMI_TX>;
reg-io-width = <1>;
status = "disabled";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
hdmi_tx_from_pvi: endpoint {
remote-endpoint = <&pvi_to_hdmi_tx>;
};
};
port@1 {
reg = <1>;
/* Point endpoint to the HDMI connector */
};
};
};
hdmi_tx_phy: phy@32fdff00 {
compatible = "fsl,imx8mp-hdmi-phy";
reg = <0x32fdff00 0x100>;
clocks = <&clk IMX8MP_CLK_HDMI_APB>,
<&clk IMX8MP_CLK_HDMI_24M>;
clock-names = "apb", "ref";
assigned-clocks = <&clk IMX8MP_CLK_HDMI_24M>;
assigned-clock-parents = <&clk IMX8MP_CLK_24M>;
power-domains = <&hdmi_blk_ctrl IMX8MP_HDMIBLK_PD_HDMI_TX_PHY>;
#clock-cells = <0>;
#phy-cells = <0>;
status = "disabled";
};
};
pcie: pcie@33800000 {
@@ -1915,8 +2195,11 @@
pcie_ep: pcie-ep@33800000 {
compatible = "fsl,imx8mp-pcie-ep";
reg = <0x33800000 0x000400000>, <0x18000000 0x08000000>;
reg-names = "dbi", "addr_space";
reg = <0x33800000 0x100000>,
<0x18000000 0x8000000>,
<0x33900000 0x100000>,
<0x33b00000 0x100000>;
reg-names = "dbi", "addr_space", "dbi2", "atu";
clocks = <&clk IMX8MP_CLK_HSIO_ROOT>,
<&clk IMX8MP_CLK_HSIO_AXI>,
<&clk IMX8MP_CLK_PCIE_ROOT>;
@@ -1950,9 +2233,9 @@
clock-names = "core", "shader", "bus", "reg";
assigned-clocks = <&clk IMX8MP_CLK_GPU3D_CORE>,
<&clk IMX8MP_CLK_GPU3D_SHADER_CORE>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>,
<&clk IMX8MP_SYS_PLL1_800M>;
assigned-clock-rates = <800000000>, <800000000>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>,
<&clk IMX8MP_SYS_PLL2_1000M>;
assigned-clock-rates = <1000000000>, <1000000000>;
power-domains = <&pgc_gpu3d>;
};
@@ -1965,8 +2248,8 @@
<&clk IMX8MP_CLK_GPU_AHB>;
clock-names = "core", "bus", "reg";
assigned-clocks = <&clk IMX8MP_CLK_GPU2D_CORE>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>;
assigned-clock-rates = <800000000>;
assigned-clock-parents = <&clk IMX8MP_SYS_PLL2_1000M>;
assigned-clock-rates = <1000000000>;
power-domains = <&pgc_gpu2d>;
};
@@ -2012,6 +2295,18 @@
interconnect-names = "g1", "g2", "vc8000e";
};
npu: npu@38500000 {
compatible = "vivante,gc";
reg = <0x38500000 0x200000>;
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_NPU_ROOT>,
<&clk IMX8MP_CLK_NPU_ROOT>,
<&clk IMX8MP_CLK_ML_AXI>,
<&clk IMX8MP_CLK_ML_AHB>;
clock-names = "core", "shader", "bus", "reg";
power-domains = <&pgc_mlmix>;
};
gic: interrupt-controller@38800000 {
compatible = "arm,gic-v3";
reg = <0x38800000 0x10000>,
@@ -2072,6 +2367,7 @@
phys = <&usb3_phy0>, <&usb3_phy0>;
phy-names = "usb2-phy", "usb3-phy";
snps,gfladj-refclk-lpm-sel-quirk;
snps,parkmode-disable-ss-quirk;
};
};
@@ -2114,6 +2410,7 @@
phys = <&usb3_phy1>, <&usb3_phy1>;
phy-names = "usb2-phy", "usb3-phy";
snps,gfladj-refclk-lpm-sel-quirk;
snps,parkmode-disable-ss-quirk;
};
};

View File

@@ -291,6 +291,12 @@ config TARGET_KONTRON_PITX_IMX8M
select IMX8MQ
select IMX8M_LPDDR4
config TARGET_TORADEX_SMARC_IMX8MP
bool "Support Toradex SMARC iMX8M Plus module"
select IMX8MP
select SUPPORT_SPL
select IMX8M_LPDDR4
config TARGET_VERDIN_IMX8MM
bool "Support Toradex Verdin iMX8M Mini module"
select IMX8MM
@@ -410,6 +416,7 @@ source "board/purism/librem5/Kconfig"
source "board/ronetix/imx8mq-cm/Kconfig"
source "board/technexion/pico-imx8mq/Kconfig"
source "board/variscite/imx8mn_var_som/Kconfig"
source "board/toradex/smarc-imx8mp/Kconfig"
source "board/toradex/verdin-imx8mm/Kconfig"
source "board/toradex/verdin-imx8mp/Kconfig"

View File

@@ -1,26 +1,42 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
#include <env/phytec/rauc.env>
#include <env/phytec/overlays.env>
bootcmd=
mmc dev ${mmcdev};
if mmc rescan; then
if test ${doraucboot} = 1; then
run raucinit;
fi;
if run loadimage; then
run mmcboot;
else
run netboot;
fi;
fi;
image=Image
console=ttyLP0
fdt_addr_r=0x83000000
fdtoverlay_addr_r=0x830c0000
bootenv_addr_r=0x83500000
fdt_addr_r=0x90000000
fdtoverlay_addr_r=0x900c0000
bootenv_addr_r=0x90500000
fdtfile=CONFIG_DEFAULT_FDT_FILE
ip_dyn=yes
prepare_mcore=setenv optargs "${optargs} clk-imx93.mcore_booted"
mmcdev=CONFIG_SYS_MMC_ENV_DEV
mmcpart=1
mmcroot=2
mmcautodetect=yes
mmcargs=setenv bootargs console=${console},${baudrate} earlycon
root=/dev/mmcblk${mmcdev}p${mmcroot} ${raucargs} rootwait rw
root=/dev/mmcblk${mmcdev}p${mmcroot} ${raucargs} rootwait rw ${optargs}
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr_r} ${fdtfile}
mmcboot=
echo Booting from mmc ...;
if run mmc_load_bootenv; then
env import -t ${bootenv_addr_r} ${filesize};
if test ${no_bootenv} = 0; then
if run mmc_load_bootenv; then
env import -t ${bootenv_addr_r} ${filesize};
fi;
fi;
run mmcargs;
if run loadfdt; then
@@ -31,7 +47,7 @@ mmcboot=
fi;
nfsroot=/nfs
netargs=setenv bootargs console=${console},${baudrate} earlycon
root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp
root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp ${optargs}
netboot=
echo Booting from net ...;
run netargs;
@@ -40,8 +56,10 @@ netboot=
else
setenv get_cmd tftp;
fi;
if run net_load_bootenv; then
env import -t ${bootenv_addr_r} ${filesize};
if test ${no_bootenv} = 0; then
if run net_load_bootenv; then
env import -t ${bootenv_addr_r} ${filesize};
fi;
fi;
${get_cmd} ${loadaddr} ${image};
if ${get_cmd} ${fdt_addr_r} ${fdtfile}; then

View File

@@ -466,10 +466,12 @@ static iomux_v3_cfg_t const rgb_pads[] = {
MX6_PAD_EIM_D31__IPU1_DISP1_DATA20 | MUX_PAD_CTRL(OUTPUT_RGB),
};
#ifdef CONFIG_IMX_HDMI
static void do_enable_hdmi(struct display_info_t const *dev)
{
imx_enable_hdmi_phy();
}
#endif
static void enable_lvds(struct display_info_t const *dev)
{
@@ -499,7 +501,9 @@ static int detect_default(struct display_info_t const *dev)
return 1;
}
struct display_info_t const displays[] = {{
struct display_info_t const displays[] = {
#ifdef CONFIG_IMX_HDMI
{
.bus = -1,
.addr = 0,
.pixfmt = IPU_PIX_FMT_RGB24,
@@ -519,7 +523,9 @@ struct display_info_t const displays[] = {{
.vsync_len = 10,
.sync = FB_SYNC_EXT,
.vmode = FB_VMODE_NONINTERLACED
} }, {
} },
#endif
{
.bus = -1,
.addr = 0,
.di = 1,
@@ -589,7 +595,11 @@ static void setup_display(void)
int reg;
enable_ipu_clock();
#ifdef CONFIG_IMX_HDMI
imx_setup_hdmi();
#endif
/* Turn on LDB0,IPU,IPU DI0 clocks */
reg = __raw_readl(&mxc_ccm->CCGR3);
reg |= MXC_CCM_CCGR3_LDB_DI0_MASK;

View File

@@ -164,6 +164,8 @@ const struct toradex_som toradex_modules[] = {
{ APALIS_IMX8QP_WIFI_BT_1300MHZ, "Apalis iMX8QP 2GB WB", TARGET_IS_ENABLED(APALIS_IMX8) },
{ APALIS_IMX8QP_1300MHZ, "Apalis iMX8QP 2GB", TARGET_IS_ENABLED(APALIS_IMX8) },
{ APALIS_IMX8QM_8GB_WIFI_BT_IT_1300MHZ, "Apalis iMX8QM 8GB WB IT", TARGET_IS_ENABLED(APALIS_IMX8) },
{ SMARC_IMX95_HEXA_8GB_WB_IT, "SMARC iMX95 Hexa 8GB WB IT", TARGET_IS_ENABLED(TORADEX_SMARC_IMX95) },
{ SMARC_IMX8MPQ_4GB_WB_IT, "SMARC iMX8M Plus Quad 4GB WB IT", TARGET_IS_ENABLED(TORADEX_SMARC_IMX8MP) },
};
struct pid4list {

View File

@@ -122,6 +122,8 @@ enum {
APALIS_IMX8QP_WIFI_BT_1300MHZ,
APALIS_IMX8QP_1300MHZ,
APALIS_IMX8QM_8GB_WIFI_BT_IT_1300MHZ, /* 95 */
SMARC_IMX95_HEXA_8GB_WB_IT,
SMARC_IMX8MPQ_4GB_WB_IT,
};
enum {

View File

@@ -0,0 +1,39 @@
if TARGET_TORADEX_SMARC_IMX8MP
config IMX_CONFIG
default "board/toradex/smarc-imx8mp/imximage.cfg"
config SYS_BOARD
default "smarc-imx8mp"
config SYS_CONFIG_NAME
default "toradex-smarc-imx8mp"
config SYS_VENDOR
default "toradex"
config TDX_CFG_BLOCK
default y
config TDX_CFG_BLOCK_2ND_ETHADDR
default y
config TDX_CFG_BLOCK_DEV
default "0"
# Toradex config block in eMMC, at the end of 1st "boot sector"
config TDX_CFG_BLOCK_OFFSET
default "-512"
config TDX_CFG_BLOCK_PART
default "1"
config TDX_HAVE_EEPROM_EXTRA
default y
config TDX_HAVE_MMC
default y
source "board/toradex/common/Kconfig"
endif

View File

@@ -0,0 +1,10 @@
Toradex Smarc iMX8M Plus
F: arch/arm/dts/imx8mp-toradex-smarc-dev-u-boot.dtsi
F: board/toradex/smarc-imx8mp/
F: board/toradex/common/
F: configs/toradex-smarc-imx8mp_defconfig
F: doc/board/toradex/toradex-smarc-imx8mp.rst
F: include/configs/toradex-smarc-imx8mp.h
M: Francesco Dolcini <francesco.dolcini@toradex.com>
S: Maintained
W: https://www.toradex.com/computer-on-modules/smarc-arm-family/nxp-imx-8m-plus

View File

@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2024 Toradex
obj-y += smarc-imx8mp.o
ifdef CONFIG_SPL_BUILD
obj-y += spl.o
obj-$(CONFIG_IMX8M_LPDDR4) += lpddr4_timing.o
endif

View File

@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2024 Toradex */
ROM_VERSION v2
BOOT_FROM emmc_fastboot
LOADER u-boot-spl-ddr.bin 0x920000

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2024 Toradex */
#ifndef __LPDDR4_TIMING_H__
#define __LPDDR4_TIMING_H__
void lpddr4_single_rank_training_patch(void);
#endif /* __LPDDR4_TIMING_H__ */

View File

@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (C) 2024 Toradex */
#include <init.h>
#include <asm/global_data.h>
#include <asm-generic/gpio.h>
#include <linux/errno.h>
#include "../common/tdx-cfg-block.h"
DECLARE_GLOBAL_DATA_PTR;
int board_init(void)
{
return 0;
}
int board_phys_sdram_size(phys_size_t *size)
{
if (!size)
return -EINVAL;
*size = get_ram_size((void *)PHYS_SDRAM, PHYS_SDRAM_SIZE + PHYS_SDRAM_2_SIZE);
return 0;
}
#if IS_ENABLED(CONFIG_OF_LIBFDT) && IS_ENABLED(CONFIG_OF_BOARD_SETUP)
static bool board_has_wifi(void)
{
struct gpio_desc *desc;
if (!gpio_hog_lookup_name("BT_UART_RXD_GPIO", &desc))
return !!dm_gpio_get_value(desc);
return true;
}
/*
* Module variants with a Wi-Fi/Bluetooth module use UART3 for Bluetooth,
* those without use UART3 as the SMARC SER3 UART.
* Test for a Wi-Fi module and if none found reassign UART3 interface to
* the SMARC SER3 pins.
*/
static void ft_board_assign_uart(void *blob)
{
const char *uart_path = "/soc@0/bus@30800000/spba-bus@30800000/serial@30880000";
const char *pinctrl_path = "/soc@0/bus@30000000/pinctrl@30330000/uart3grp";
int pinctrl_offset;
int uart_offset;
int bt_offset;
u32 phandle;
if (board_has_wifi())
return;
uart_offset = fdt_path_offset(blob, uart_path);
if (uart_offset < 0)
return;
fdt_delprop(blob, uart_offset, "uart-has-rtscts");
bt_offset = fdt_subnode_offset(blob, uart_offset, "bluetooth");
if (bt_offset < 0)
return;
fdt_del_node(blob, bt_offset);
pinctrl_offset = fdt_path_offset(blob, pinctrl_path);
if (pinctrl_offset < 0)
return;
phandle = fdt_get_phandle(blob, pinctrl_offset);
if (phandle < 0)
return;
fdt_setprop_u32(blob, uart_offset, "pinctrl-0", phandle);
}
int ft_board_setup(void *blob, struct bd_info *bd)
{
ft_board_assign_uart(blob);
return ft_common_board_setup(blob, bd);
}
#endif

View File

@@ -0,0 +1,20 @@
boot_script_dhcp=boot.scr
boot_targets=mmc1 mmc0 dhcp
console=ttymxc1
fdt_addr_r=0x50200000
fdt_board=dev
initrd_addr=0x43800000
initrd_high=0xffffffffffffffff
kernel_addr_r=CONFIG_SYS_LOAD_ADDR
kernel_comp_addr_r=0x40200000
kernel_comp_size=0x08000000
ramdisk_addr_r=0x50300000
scriptaddr=0x50280000
update_uboot=
askenv confirm Did you load flash.bin (y/N)?;
if test $confirm = y; then
setexpr blkcnt ${filesize} + 0x1ff && setexpr blkcnt
${blkcnt} / 0x200; mmc dev 0 1; mmc write ${loadaddr} 0x0
${blkcnt};
fi

View File

@@ -0,0 +1,130 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (C) 2024 Toradex */
#include <hang.h>
#include <init.h>
#include <log.h>
#include <spl.h>
#include <asm/arch/clock.h>
#include <asm/arch/ddr.h>
#include <asm/arch/sys_proto.h>
#include <asm/global_data.h>
#include <asm/mach-imx/boot_mode.h>
#include <dm/device.h>
#include <power/pmic.h>
#include <power/pca9450.h>
#include "lpddr4_timing.h"
DECLARE_GLOBAL_DATA_PTR;
int spl_board_boot_device(enum boot_device boot_dev_spl)
{
return BOOT_DEVICE_BOOTROM;
}
void spl_dram_init(void)
{
/*
* Try configuring for dual rank memory falling back to single rank
*/
if (!ddr_init(&dram_timing)) {
puts("DDR configured as dual rank\n");
return;
}
lpddr4_single_rank_training_patch();
if (!ddr_init(&dram_timing)) {
puts("DDR configured as single rank\n");
return;
}
puts("DDR configuration failed\n");
}
void spl_board_init(void)
{
arch_misc_init();
/*
* Set GIC clock to 500Mhz for OD VDD_SOC. Kernel driver does
* not allow to change it. Should set the clock after PMIC
* setting done. Default is 400Mhz (system_pll1_800m with div = 2)
* set by ROM for ND VDD_SOC
*/
clock_enable(CCGR_GIC, 0);
clock_set_target_val(GIC_CLK_ROOT, CLK_ROOT_ON | CLK_ROOT_SOURCE_SEL(5));
clock_enable(CCGR_GIC, 1);
puts("Normal Boot\n");
}
int power_init_board(void)
{
struct udevice *dev;
int ret;
ret = pmic_get("pmic@25", &dev);
if (ret == -ENODEV) {
puts("No pmic@25\n");
return 0;
}
if (ret < 0)
return ret;
/* BUCKxOUT_DVS0/1 control BUCK123 output */
pmic_reg_write(dev, PCA9450_BUCK123_DVS, 0x29);
/*
* Increase VDD_SOC to typical value 0.95V before first
* DRAM access, set DVS1 to 0.85V for suspend.
* Enable DVS control through PMIC_STBY_REQ and
* set B1_ENMODE=1 (ON by PMIC_ON_REQ=H)
*/
if (IS_ENABLED(CONFIG_IMX8M_VDD_SOC_850MV))
/* set DVS0 to 0.85v for special case */
pmic_reg_write(dev, PCA9450_BUCK1OUT_DVS0, 0x14);
else
pmic_reg_write(dev, PCA9450_BUCK1OUT_DVS0, 0x1c);
pmic_reg_write(dev, PCA9450_BUCK1OUT_DVS1, 0x14);
pmic_reg_write(dev, PCA9450_BUCK1CTRL, 0x59);
/*
* Kernel uses OD/OD freq for SOC.
* To avoid timing risk from SOC to ARM,increase VDD_ARM to OD
* voltage 0.95V.
*/
pmic_reg_write(dev, PCA9450_BUCK2OUT_DVS0, 0x1c);
/* set LDO4 and CONFIG2 to enable the I2C level translator */
pmic_reg_write(dev, PCA9450_LDO4CTRL, 0x59);
pmic_reg_write(dev, PCA9450_CONFIG2, 0x1);
return 0;
}
/* Do not use BSS area in this phase */
void board_init_f(ulong dummy)
{
int ret;
arch_cpu_init();
init_uart_clk(3);
ret = spl_early_init();
if (ret) {
debug("spl_init() failed: %d\n", ret);
hang();
}
preloader_console_init();
enable_tzc380();
/* PMIC initialization */
power_init_board();
/* DDR initialization */
spl_dram_init();
}

View File

@@ -35,7 +35,6 @@ CONFIG_REMAKE_ELF=y
# CONFIG_ANDROID_BOOT_IMAGE is not set
CONFIG_DISTRO_DEFAULTS=y
CONFIG_OF_SYSTEM_SETUP=y
CONFIG_BOOTCOMMAND="mmc dev ${mmcdev}; if mmc rescan; then if run loadimage; then run mmcboot; else run netboot; fi; fi;"
CONFIG_DEFAULT_FDT_FILE="oftree"
CONFIG_SYS_CBSIZE=2048
CONFIG_SYS_PBSIZE=2074

View File

@@ -256,6 +256,8 @@ CONFIG_CONSOLE_TRUETYPE=y
CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
CONFIG_I2C_EDID=y
CONFIG_VIDEO_SANDBOX_SDL=y
CONFIG_VIDEO_BRIDGE=y
CONFIG_VIDEO_BRIDGE_LVDS_CODEC=y
CONFIG_OSD=y
CONFIG_SANDBOX_OSD=y
CONFIG_BMP_16BPP=y

View File

@@ -220,6 +220,8 @@ CONFIG_CONSOLE_TRUETYPE=y
CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
CONFIG_I2C_EDID=y
CONFIG_VIDEO_SANDBOX_SDL=y
CONFIG_VIDEO_BRIDGE=y
CONFIG_VIDEO_BRIDGE_LVDS_CODEC=y
CONFIG_OSD=y
CONFIG_SANDBOX_OSD=y
CONFIG_BMP_16BPP=y

View File

@@ -0,0 +1,184 @@
CONFIG_ARM=y
CONFIG_ARCH_IMX8M=y
CONFIG_TEXT_BASE=0x40200000
CONFIG_SPL_GPIO=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_NR_DRAM_BANKS=2
CONFIG_ENV_SIZE=0x2000
CONFIG_ENV_OFFSET=0xFFFFDE00
CONFIG_DM_GPIO=y
CONFIG_DEFAULT_DEVICE_TREE="imx8mp-toradex-smarc-dev"
CONFIG_SPL_TEXT_BASE=0x920000
CONFIG_TARGET_TORADEX_SMARC_IMX8MP=y
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_DM_RESET=y
CONFIG_SYS_MONITOR_LEN=524288
CONFIG_SPL_MMC=y
CONFIG_SPL_SERIAL=y
CONFIG_SPL_DRIVERS_MISC=y
CONFIG_SPL_STACK=0x960000
CONFIG_SPL_SYS_MALLOC_F_LEN=0x4000
CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
CONFIG_SPL_BSS_START_ADDR=0x98fc00
CONFIG_SPL_BSS_MAX_SIZE=0x400
CONFIG_SPL=y
CONFIG_IMX_BOOTAUX=y
CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x48000000
CONFIG_SYS_LOAD_ADDR=0x48200000
CONFIG_PCI=y
CONFIG_SYS_MEMTEST_START=0x40000000
CONFIG_SYS_MEMTEST_END=0x80000000
CONFIG_REMAKE_ELF=y
CONFIG_FIT=y
CONFIG_FIT_EXTERNAL_OFFSET=0x3000
CONFIG_FIT_VERBOSE=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_BOOTSTD_FULL=y
# CONFIG_BOOTSTD_BOOTCOMMAND is not set
CONFIG_BOOTDELAY=1
CONFIG_OF_SYSTEM_SETUP=y
CONFIG_BOOTCOMMAND="bootflow scan -b"
CONFIG_USE_PREBOOT=y
CONFIG_PREBOOT="test -n ${fdtfile} || setenv fdtfile imx8mp-toradex-smarc-dev.dtb"
CONFIG_SYS_CBSIZE=2048
CONFIG_SYS_PBSIZE=2081
CONFIG_LOG=y
# CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_ARCH_MISC_INIT=y
CONFIG_SPL_MAX_SIZE=0x26000
CONFIG_SPL_BOARD_INIT=y
CONFIG_SPL_BOOTROM_SUPPORT=y
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
CONFIG_SPL_SYS_MALLOC=y
CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y
CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x42200000
CONFIG_SPL_SYS_MALLOC_SIZE=0x80000
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x300
CONFIG_SPL_I2C=y
CONFIG_SPL_POWER=y
CONFIG_SPL_WATCHDOG=y
CONFIG_SYS_PROMPT="SMARC iMX8MP # "
# CONFIG_BOOTM_NETBSD is not set
CONFIG_CMD_ASKENV=y
# CONFIG_CMD_EXPORTENV is not set
CONFIG_CRC32_VERIFY=y
CONFIG_CMD_MD5SUM=y
CONFIG_MD5SUM_VERIFY=y
CONFIG_CMD_MEMTEST=y
CONFIG_CMD_CLK=y
CONFIG_CMD_FUSE=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_PCI=y
CONFIG_CMD_READ=y
CONFIG_CMD_USB=y
CONFIG_CMD_USB_MASS_STORAGE=y
CONFIG_CMD_BOOTCOUNT=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_TIME=y
CONFIG_CMD_SYSBOOT=y
CONFIG_CMD_UUID=y
CONFIG_CMD_REGULATOR=y
CONFIG_CMD_EXT4_WRITE=y
# CONFIG_ISO_PARTITION is not set
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_OF_CONTROL=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_ENV_OVERWRITE=y
CONFIG_ENV_IS_IN_MMC=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_SYS_MMC_ENV_DEV=0
CONFIG_SYS_MMC_ENV_PART=1
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
CONFIG_USE_ETHPRIME=y
CONFIG_ETHPRIME="eth0"
CONFIG_VERSION_VARIABLE=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_IP_DEFRAG=y
CONFIG_TFTP_BLOCKSIZE=4096
CONFIG_SPL_DM=y
CONFIG_BOOTCOUNT_LIMIT=y
CONFIG_BOOTCOUNT_ENV=y
CONFIG_CLK_COMPOSITE_CCF=y
CONFIG_CLK_IMX8MP=y
CONFIG_FSL_CAAM=y
CONFIG_USB_FUNCTION_FASTBOOT=y
CONFIG_FASTBOOT_BUF_ADDR=0x44200000
CONFIG_FASTBOOT_FLASH=y
CONFIG_FASTBOOT_UUU_SUPPORT=y
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
CONFIG_GPIO_HOG=y
CONFIG_SPL_GPIO_HOG=y
CONFIG_MXC_GPIO=y
CONFIG_DM_PCA953X=y
CONFIG_DM_I2C=y
CONFIG_LED=y
CONFIG_LED_GPIO=y
CONFIG_I2C_EEPROM=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_SPL_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
CONFIG_SPL_MMC_UHS_SUPPORT=y
CONFIG_MMC_HS400_ES_SUPPORT=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_SPL_MMC_HS400_SUPPORT=y
CONFIG_FSL_USDHC=y
CONFIG_PHY_ADDR_ENABLE=y
CONFIG_PHY_TI_DP83867=y
CONFIG_DM_MDIO=y
CONFIG_DM_ETH_PHY=y
CONFIG_DWC_ETH_QOS=y
CONFIG_DWC_ETH_QOS_IMX=y
CONFIG_FEC_MXC=y
CONFIG_RGMII=y
CONFIG_MII=y
CONFIG_NVME_PCI=y
CONFIG_PCIE_DW_IMX=y
CONFIG_PHY=y
CONFIG_PHY_IMX8MQ_USB=y
CONFIG_PHY_IMX8M_PCIE=y
CONFIG_PINCTRL=y
CONFIG_SPL_PINCTRL=y
CONFIG_PINCTRL_IMX8M=y
CONFIG_POWER_DOMAIN=y
CONFIG_IMX8M_POWER_DOMAIN=y
CONFIG_IMX8MP_HSIOMIX_BLKCTRL=y
CONFIG_DM_PMIC=y
CONFIG_DM_PMIC_PCA9450=y
CONFIG_SPL_DM_PMIC_PCA9450=y
CONFIG_DM_REGULATOR_PCA9450=y
CONFIG_SPL_DM_REGULATOR_PCA9450=y
CONFIG_DM_REGULATOR_FIXED=y
CONFIG_DM_REGULATOR_GPIO=y
CONFIG_DM_SERIAL=y
CONFIG_MXC_UART=y
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_SYSRESET_PSCI=y
CONFIG_SYSRESET_WATCHDOG=y
CONFIG_DM_THERMAL=y
CONFIG_IMX_TMU=y
CONFIG_USB=y
# CONFIG_SPL_DM_USB is not set
CONFIG_DM_USB_GADGET=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_XHCI_DWC3_OF_SIMPLE=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_MX7 is not set
CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_GENERIC=y
CONFIG_USB_KEYBOARD=y
CONFIG_USB_HOST_ETHER=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_MANUFACTURER="Toradex"
CONFIG_USB_GADGET_VENDOR_NUM=0x1b67
CONFIG_USB_GADGET_PRODUCT_NUM=0x4000
CONFIG_IMX_WATCHDOG=y
CONFIG_HEXDUMP=y

View File

@@ -9,6 +9,7 @@ Toradex
apalis-imx8
colibri_imx7
colibri-imx8x
smarc-imx8mp
verdin-am62
verdin-imx8mm
verdin-imx8mp

View File

@@ -0,0 +1,116 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
Toradex SMARC iMX8M Plus Module
===============================
- SoM: https://www.toradex.com/computer-on-modules/smarc-arm-family/nxp-imx-8m-plus
- Carrier board: https://www.toradex.com/products/carrier-board/smarc-development-board-kit
Quick Start
-----------
- Build the ARM trusted firmware binary
- Get the DDR firmware
- Build U-Boot
- Flash to eMMC
- Boot
Get and Build the ARM Trusted Firmware (Trusted Firmware A)
-----------------------------------------------------------
.. code-block:: bash
$ echo "Downloading and building TF-A..."
$ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
$ cd trusted-firmware-a
Then build ATF (TF-A):
.. code-block:: bash
$ export CROSS_COMPILE=aarch64-linux-gnu-
$ make PLAT=imx8mp IMX_BOOT_UART_BASE=0x30a60000 bl31
$ cp build/imx8mp/release/bl31.bin ../
Get the DDR Firmware
--------------------
.. code-block:: bash
$ cd ..
$ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.10.1.bin
$ chmod +x firmware-imx-8.10.1.bin
$ ./firmware-imx-8.10.1.bin
$ cp firmware-imx-8.10.1/firmware/ddr/synopsys/lpddr4*_202006.bin ./
Build U-Boot
------------
.. code-block:: bash
$ export CROSS_COMPILE=aarch64-linux-gnu-
$ make toradex-smarc-imx8mp_defconfig
$ make
Flash to eMMC
-------------
.. code-block:: bash
> tftpboot ${loadaddr} flash.bin
> setexpr blkcnt ${filesize} + 0x1ff && setexpr blkcnt ${blkcnt} / 0x200
> mmc dev 0 1 && mmc write ${loadaddr} 0x0 ${blkcnt}
As a convenience, instead of the last two commands, one may also use the update
U-Boot wrapper:
.. code-block:: bash
> run update_uboot
Boot
----
ATF, U-Boot proper and u-boot.dtb images are packed into a FIT image,
which is loaded and parsed by SPL.
Boot sequence is:
* SPL ---> ATF (TF-A) ---> U-Boot proper
Output::
U-Boot SPL 2025.04-rc5-00023-g34c31be81211 (Apr 04 2025 - 15:36:23 +0100)
Training FAILED
DDR configured as single rank
SEC0: RNG instantiated
Normal Boot
Trying to boot from BOOTROM
Boot Stage: Primary boot
Find img info 0x4802f200, size 1100
Need continue download 1024
NOTICE: Do not release JR0 to NS as it can be used by HAB
NOTICE: BL31: v2.11.0(release):v2.11.0-723-gbd298f5c30ac
NOTICE: BL31: Built : 14:18:43, Apr 4 2025
U-Boot 2025.04-rc5-00023-g34c31be81211 (Apr 04 2025 - 15:36:23 +0100)
CPU: Freescale i.MX8MP[8] rev1.1 1600 MHz (running at 1200 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 72C
Reset cause: POR
DRAM: 4 GiB
Core: 312 devices, 32 uclasses, devicetree: separate
WDT: Started watchdog@30280000 with servicing every 1000ms (60s timeout)
MMC: FSL_SDHC: 1, FSL_SDHC: 0
Loading Environment from MMC... Reading from MMC(0)... OK
In: serial@30a60000
Out: serial@30a60000
Err: serial@30a60000
Model: Toradex 0097 SMARC iMX8M Plus Quad 4GB WB IT V1.0A
Serial#: 15603364
SEC0: RNG instantiated
Net: Get shared mii bus on ethernet@30be0000
eth1: ethernet@30be0000, eth0: ethernet@30bf0000 [PRIME]
Hit any key to stop autoboot: 0
SMARC iMX8MP #

View File

@@ -312,7 +312,7 @@ drivers/demo/demo-shape.c):
.name = "demo_shape_drv",
.id = UCLASS_DEMO,
.ops = &shape_ops,
.priv_data_size = sizeof(struct shape_data),
.priv_auto = sizeof(struct shape_data),
};

View File

@@ -623,14 +623,27 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (!ops->set_parent)
return -ENOSYS;
ret = ops->set_parent(clk, parent);
if (ret)
ret = clk_enable(parent);
if (ret) {
printf("Cannot enable parent %s\n", parent->dev->name);
return ret;
}
if (CONFIG_IS_ENABLED(CLK_CCF))
ret = ops->set_parent(clk, parent);
if (ret) {
clk_disable(parent);
return ret;
}
if (CONFIG_IS_ENABLED(CLK_CCF)) {
ret = device_reparent(clk->dev, parent->dev);
if (ret) {
clk_disable(parent);
return ret;
}
}
return ret;
return 0;
}
int clk_enable(struct clk *clk)

View File

@@ -14,7 +14,14 @@
#include "clk.h"
#if CONFIG_IS_ENABLED(VIDEO)
static u32 share_count_media;
#endif
static const char * const pll_ref_sels[] = { "osc_24m", "dummy", "dummy", "dummy", };
#if CONFIG_IS_ENABLED(VIDEO)
static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
#endif
static const char * const dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", };
static const char * const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", };
static const char * const sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", };
@@ -31,6 +38,12 @@ static const char * const imx8mp_hsio_axi_sels[] = {"osc_24m", "sys_pll2_500m",
"sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
"clk_ext4", "audio_pll2_out", };
#if CONFIG_IS_ENABLED(VIDEO)
static const char * const imx8mp_media_isp_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m",
"sys_pll3_out", "sys_pll1_400m", "audio_pll2_out",
"clk_ext1", "sys_pll2_500m", };
#endif
static const char * const imx8mp_main_axi_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll1_800m",
"sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out",
"video_pll1_out", "sys_pll1_100m",};
@@ -43,6 +56,16 @@ static const char * const imx8mp_nand_usdhc_sels[] = {"osc_24m", "sys_pll1_266m"
"sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll1_out", };
#if CONFIG_IS_ENABLED(VIDEO)
static const char * const imx8mp_media_axi_sels[] = {"osc_24m", "sys_pll2_1000m", "sys_pll1_800m",
"sys_pll3_out", "sys_pll1_40m", "audio_pll2_out",
"clk_ext1", "sys_pll2_500m", };
static const char * const imx8mp_media_apb_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll1_800m",
"sys_pll3_out", "sys_pll1_40m", "audio_pll2_out",
"clk_ext1", "sys_pll1_133m", };
#endif
static const char * const imx8mp_noc_sels[] = {"osc_24m", "sys_pll1_800m", "sys_pll3_out",
"sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out",
"video_pll1_out", "audio_pll2_out", };
@@ -175,6 +198,17 @@ static const char * const imx8mp_usdhc3_sels[] = {"osc_24m", "sys_pll1_400m", "s
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
#if CONFIG_IS_ENABLED(VIDEO)
static const char * const imx8mp_media_disp_pix_sels[] = {"osc_24m", "video_pll1_out", "audio_pll2_out",
"audio_pll1_out", "sys_pll1_800m",
"sys_pll2_1000m", "sys_pll3_out", "clk_ext4", };
static const char * const imx8mp_media_ldb_sels[] = {"osc_24m", "sys_pll2_333m", "sys_pll2_100m",
"sys_pll1_800m", "sys_pll2_1000m",
"clk_ext2", "audio_pll2_out",
"video_pll1_out", };
#endif
static const char * const imx8mp_enet_ref_sels[] = {"osc_24m", "sys_pll2_125m", "sys_pll2_50m",
"sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
"video_pll1_out", "clk_ext4", };
@@ -199,12 +233,19 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_DUMMY, clk_register_fixed_rate(NULL, "dummy", 0));
#if CONFIG_IS_ENABLED(VIDEO)
clk_dm(IMX8MP_VIDEO_PLL1_REF_SEL, imx_clk_mux(dev, "video_pll1_ref_sel", base + 0x28, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
#endif
clk_dm(IMX8MP_DRAM_PLL_REF_SEL, imx_clk_mux(dev, "dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MP_ARM_PLL_REF_SEL, imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MP_SYS_PLL1_REF_SEL, imx_clk_mux(dev, "sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MP_SYS_PLL2_REF_SEL, imx_clk_mux(dev, "sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
clk_dm(IMX8MP_SYS_PLL3_REF_SEL, imx_clk_mux(dev, "sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
#if CONFIG_IS_ENABLED(VIDEO)
clk_dm(IMX8MP_VIDEO_PLL1, imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", base + 0x28,
&imx_1443x_pll));
#endif
clk_dm(IMX8MP_DRAM_PLL, imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50,
&imx_1443x_dram_pll));
clk_dm(IMX8MP_ARM_PLL, imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84,
@@ -216,12 +257,18 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_SYS_PLL3, imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114,
&imx_1416x_pll));
#if CONFIG_IS_ENABLED(VIDEO)
clk_dm(IMX8MP_VIDEO_PLL1_BYPASS, imx_clk_mux_flags(dev, "video_pll1_bypass", base + 0x28, 16, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels), CLK_SET_RATE_PARENT));
#endif
clk_dm(IMX8MP_DRAM_PLL_BYPASS, imx_clk_mux_flags(dev, "dram_pll_bypass", base + 0x50, 4, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT));
clk_dm(IMX8MP_ARM_PLL_BYPASS, imx_clk_mux_flags(dev, "arm_pll_bypass", base + 0x84, 4, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT));
clk_dm(IMX8MP_SYS_PLL1_BYPASS, imx_clk_mux_flags(dev, "sys_pll1_bypass", base + 0x94, 4, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT));
clk_dm(IMX8MP_SYS_PLL2_BYPASS, imx_clk_mux_flags(dev, "sys_pll2_bypass", base + 0x104, 4, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT));
clk_dm(IMX8MP_SYS_PLL3_BYPASS, imx_clk_mux_flags(dev, "sys_pll3_bypass", base + 0x114, 4, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT));
#if CONFIG_IS_ENABLED(VIDEO)
clk_dm(IMX8MP_VIDEO_PLL1_OUT, imx_clk_gate(dev, "video_pll1_out", "video_pll1_bypass", base + 0x28, 13));
#endif
clk_dm(IMX8MP_DRAM_PLL_OUT, imx_clk_gate(dev, "dram_pll_out", "dram_pll_bypass", base + 0x50, 13));
clk_dm(IMX8MP_ARM_PLL_OUT, imx_clk_gate(dev, "arm_pll_out", "arm_pll_bypass", base + 0x84, 11));
clk_dm(IMX8MP_SYS_PLL1_OUT, imx_clk_gate(dev, "sys_pll1_out", "sys_pll1_bypass", base + 0x94, 11));
@@ -267,13 +314,23 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_A53_DIV, imx_clk_divider2(dev, "arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3));
clk_dm(IMX8MP_CLK_HSIO_AXI, imx8m_clk_composite(dev, "hsio_axi", imx8mp_hsio_axi_sels, base + 0x8380));
#if CONFIG_IS_ENABLED(VIDEO)
clk_dm(IMX8MP_CLK_MEDIA_ISP, imx8m_clk_composite(dev, "media_isp", imx8mp_media_isp_sels, base + 0x8400));
#endif
clk_dm(IMX8MP_CLK_MAIN_AXI, imx8m_clk_composite_critical(dev, "main_axi", imx8mp_main_axi_sels, base + 0x8800));
clk_dm(IMX8MP_CLK_ENET_AXI, imx8m_clk_composite_critical(dev, "enet_axi", imx8mp_enet_axi_sels, base + 0x8880));
clk_dm(IMX8MP_CLK_NAND_USDHC_BUS, imx8m_clk_composite_critical(dev, "nand_usdhc_bus", imx8mp_nand_usdhc_sels, base + 0x8900));
#if CONFIG_IS_ENABLED(VIDEO)
clk_dm(IMX8MP_CLK_MEDIA_AXI, imx8m_clk_composite(dev, "media_axi", imx8mp_media_axi_sels, base + 0x8a00));
clk_dm(IMX8MP_CLK_MEDIA_APB, imx8m_clk_composite(dev, "media_apb", imx8mp_media_apb_sels, base + 0x8a80));
#endif
clk_dm(IMX8MP_CLK_NOC, imx8m_clk_composite_critical(dev, "noc", imx8mp_noc_sels, base + 0x8d00));
clk_dm(IMX8MP_CLK_NOC_IO, imx8m_clk_composite_critical(dev, "noc_io", imx8mp_noc_io_sels, base + 0x8d80));
clk_dm(IMX8MP_CLK_AHB, imx8m_clk_composite_critical(dev, "ahb_root", imx8mp_ahb_sels, base + 0x9000));
#if CONFIG_IS_ENABLED(VIDEO)
clk_dm(IMX8MP_CLK_MEDIA_DISP2_PIX, imx8m_clk_composite(dev, "media_disp2_pix", imx8mp_media_disp_pix_sels, base + 0x9300));
#endif
clk_dm(IMX8MP_CLK_IPG_ROOT, imx_clk_divider2(dev, "ipg_root", "ahb_root", base + 0x9080, 0, 1));
@@ -312,6 +369,10 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_WDOG, imx8m_clk_composite(dev, "wdog", imx8mp_wdog_sels, base + 0xb900));
clk_dm(IMX8MP_CLK_USDHC3, imx8m_clk_composite(dev, "usdhc3", imx8mp_usdhc3_sels, base + 0xbc80));
#if CONFIG_IS_ENABLED(VIDEO)
clk_dm(IMX8MP_CLK_MEDIA_DISP1_PIX, imx8m_clk_composite(dev, "media_disp1_pix", imx8mp_media_disp_pix_sels, base + 0xbe00));
clk_dm(IMX8MP_CLK_MEDIA_LDB, imx8m_clk_composite(dev, "media_ldb", imx8mp_media_ldb_sels, base + 0xbf00));
#endif
clk_dm(IMX8MP_CLK_DRAM_ALT_ROOT, imx_clk_fixed_factor(dev, "dram_alt_root", "dram_alt", 1, 4));
clk_dm(IMX8MP_CLK_DRAM_CORE, imx_clk_mux2_flags(dev, "dram_core_clk", base + 0x9800, 24, 1, imx8mp_dram_core_sels, ARRAY_SIZE(imx8mp_dram_core_sels), CLK_IS_CRITICAL));
@@ -355,6 +416,14 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_WDOG2_ROOT, imx_clk_gate4(dev, "wdog2_root_clk", "wdog", base + 0x4540, 0));
clk_dm(IMX8MP_CLK_WDOG3_ROOT, imx_clk_gate4(dev, "wdog3_root_clk", "wdog", base + 0x4550, 0));
clk_dm(IMX8MP_CLK_HSIO_ROOT, imx_clk_gate4(dev, "hsio_root_clk", "ipg_root", base + 0x45c0, 0));
#if CONFIG_IS_ENABLED(VIDEO)
clk_dm(IMX8MP_CLK_MEDIA_APB_ROOT, imx_clk_gate2_shared2(dev, "media_apb_root_clk", "media_apb", base + 0x45d0, 0, &share_count_media));
clk_dm(IMX8MP_CLK_MEDIA_AXI_ROOT, imx_clk_gate2_shared2(dev, "media_axi_root_clk", "media_axi", base + 0x45d0, 0, &share_count_media));
clk_dm(IMX8MP_CLK_MEDIA_DISP1_PIX_ROOT, imx_clk_gate2_shared2(dev, "media_disp1_pix_root_clk", "media_disp1_pix", base + 0x45d0, 0, &share_count_media));
clk_dm(IMX8MP_CLK_MEDIA_DISP2_PIX_ROOT, imx_clk_gate2_shared2(dev, "media_disp2_pix_root_clk", "media_disp2_pix", base + 0x45d0, 0, &share_count_media));
clk_dm(IMX8MP_CLK_MEDIA_LDB_ROOT, imx_clk_gate2_shared2(dev, "media_ldb_root_clk", "media_ldb", base + 0x45d0, 0, &share_count_media));
clk_dm(IMX8MP_CLK_MEDIA_ISP_ROOT, imx_clk_gate2_shared2(dev, "media_isp_root_clk", "media_isp", base + 0x45d0, 0, &share_count_media));
#endif
clk_dm(IMX8MP_CLK_USDHC3_ROOT, imx_clk_gate4(dev, "usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));

View File

@@ -98,7 +98,7 @@ ofnode ofnode_graph_get_port_by_id(ofnode parent, u32 id)
* @id: id for the endpoint
*
* Return: ofnode in given endpoint or ofnode_null() if not found.
* reg and port_reg are ignored when they are -1.
* reg_id and id are ignored when they are -1.
*/
ofnode ofnode_graph_get_endpoint_by_regs(ofnode parent, int reg_id, int id)
{

View File

@@ -16,6 +16,7 @@
#include <dm/device.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/ofnode_graph.h>
#include <dm/uclass.h>
#include <dm/uclass-internal.h>
#include <dm/util.h>
@@ -582,6 +583,24 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
ret = uclass_find_device_by_phandle(id, parent, name, &dev);
return uclass_get_device_tail(dev, ret, devp);
}
int uclass_get_device_by_endpoint(enum uclass_id class_id, struct udevice *dev,
int port_idx, int ep_idx, struct udevice **devp)
{
ofnode node_source = dev_ofnode(dev);
ofnode node_dest = ofnode_graph_get_remote_node(node_source, port_idx, ep_idx);
struct udevice *target = NULL;
int ret;
if (!ofnode_valid(node_dest))
return -EINVAL;
ret = uclass_find_device_by_ofnode(class_id, node_dest, &target);
if (ret)
return -ENODEV;
return uclass_get_device_tail(target, 0, devp);
}
#endif
/*

View File

@@ -163,4 +163,5 @@ U_BOOT_DRIVER(sandbox_scmi_devices) = {
.priv_auto = sizeof(struct sandbox_scmi_device_priv),
.remove = sandbox_scmi_devices_remove,
.probe = sandbox_scmi_devices_probe,
.flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
};

View File

@@ -20,6 +20,16 @@
#include "smt.h"
static void scmi_smt_enable_intr(struct scmi_smt *smt, bool enable)
{
struct scmi_smt_header *hdr = (void *)smt->buf;
if (enable)
hdr->flags |= SCMI_SHMEM_FLAG_INTR_ENABLED;
else
hdr->flags &= ~SCMI_SHMEM_FLAG_INTR_ENABLED;
}
/**
* Get shared memory configuration defined by the referred DT phandle
* Return with a errno compliant value.
@@ -48,6 +58,9 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
if (!smt->buf)
return -ENOMEM;
if (device_is_compatible(dev, "arm,scmi") && ofnode_has_property(dev_ofnode(dev), "mboxes"))
scmi_smt_enable_intr(smt, true);
#ifdef CONFIG_ARM
if (dcache_status())
mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, MMU_SECTION_SIZE),

View File

@@ -47,6 +47,13 @@ config IMX8MP_HSIOMIX_BLKCTRL
help
Enable support for manipulating NXP i.MX8MP on-SoC HSIOMIX block controller.
config IMX8MP_MEDIAMIX_BLKCTRL
bool "Enable i.MX8MP MEDIAMIX domain driver"
depends on POWER_DOMAIN && IMX8MP
select CLK
help
Enable support for manipulating NXP i.MX8MP on-SoC MEDIAMIX block controller.
config MTK_POWER_DOMAIN
bool "Enable the MediaTek power domain driver"
depends on POWER_DOMAIN && ARCH_MEDIATEK

View File

@@ -9,6 +9,7 @@ obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o
obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o imx8-power-domain.o
obj-$(CONFIG_IMX8M_POWER_DOMAIN) += imx8m-power-domain.o
obj-$(CONFIG_IMX8MP_HSIOMIX_BLKCTRL) += imx8mp-hsiomix.o
obj-$(CONFIG_IMX8MP_MEDIAMIX_BLKCTRL) += imx8mp-mediamix.o
obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o
obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o
obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o

View File

@@ -40,6 +40,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define IMX8MN_MIPI_A53_DOMAIN BIT(2)
#define IMX8MP_HSIOMIX_A53_DOMAIN BIT(19)
#define IMX8MP_MEDIAMIX_A53_DOMAIN BIT(12)
#define IMX8MP_USB2_PHY_A53_DOMAIN BIT(5)
#define IMX8MP_USB1_PHY_A53_DOMAIN BIT(4)
#define IMX8MP_PCIE_PHY_A53_DOMAIN BIT(3)
@@ -63,6 +64,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define IMX8MN_MIPI_SW_Pxx_REQ BIT(0)
#define IMX8MP_HSIOMIX_Pxx_REQ BIT(17)
#define IMX8MP_MEDIAMIX_Pxx_REQ BIT(10)
#define IMX8MP_USB2_PHY_Pxx_REQ BIT(3)
#define IMX8MP_USB1_PHY_Pxx_REQ BIT(2)
#define IMX8MP_PCIE_PHY_SW_Pxx_REQ BIT(1)
@@ -81,6 +83,9 @@ DECLARE_GLOBAL_DATA_PTR;
#define IMX8MP_HSIOMIX_PWRDNACKN BIT(28)
#define IMX8MP_HSIOMIX_PWRDNREQN BIT(12)
#define IMX8MP_MEDIAMIX_PWRDNACKN BIT(30)
#define IMX8MP_MEDIAMIX_PWRDNREQN BIT(14)
/*
* The PGC offset values in Reference Manual
* (Rev. 1, 01/2018 and the older ones) GPC chapter's
@@ -101,6 +106,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define IMX8MP_PGC_PCIE 13
#define IMX8MP_PGC_USB1 14
#define IMX8MP_PGC_USB2 15
#define IMX8MP_PGC_MEDIAMIX 22
#define IMX8MP_PGC_HSIOMIX 29
#define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40)
@@ -303,6 +309,17 @@ static const struct imx_pgc_domain imx8mp_pgc_domains[] = {
.pgc = BIT(IMX8MP_PGC_HSIOMIX),
.keep_clocks = true,
},
[IMX8MP_POWER_DOMAIN_MEDIAMIX] = {
.bits = {
.pxx = IMX8MP_MEDIAMIX_Pxx_REQ,
.map = IMX8MP_MEDIAMIX_A53_DOMAIN,
.hskreq = IMX8MP_MEDIAMIX_PWRDNREQN,
.hskack = IMX8MP_MEDIAMIX_PWRDNACKN,
},
.pgc = BIT(IMX8MP_PGC_MEDIAMIX),
.keep_clocks = true,
},
};
static const struct imx_pgc_regs imx8mp_pgc_regs = {

View File

@@ -0,0 +1,208 @@
// SPDX-License-Identifier: GPL-2.0
/*
* i.MX8 MEDIAMIX control block driver
* Copyright (C) 2024 Miquel Raynal <miquel.raynal@bootlin.com>
* Inspired from Marek Vasut <marex@denx.de> work on the hsiomix driver.
*/
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <power-domain-uclass.h>
#include <linux/delay.h>
#include <dt-bindings/power/imx8mp-power.h>
#define BLK_SFT_RSTN 0x0
#define BLK_CLK_EN 0x4
struct imx8mp_mediamix_priv {
void __iomem *base;
struct clk clk_apb;
struct clk clk_axi;
struct clk clk_disp2;
struct power_domain pd_bus;
struct power_domain pd_lcdif2;
};
static int imx8mp_mediamix_on(struct power_domain *power_domain)
{
struct udevice *dev = power_domain->dev;
struct imx8mp_mediamix_priv *priv = dev_get_priv(dev);
struct power_domain *domain;
struct clk *clk;
u32 reset;
int ret;
switch (power_domain->id) {
case IMX8MP_MEDIABLK_PD_LCDIF_2:
domain = &priv->pd_lcdif2;
clk = &priv->clk_disp2;
reset = BIT(11) | BIT(12) | BIT(24);
break;
default:
return -EINVAL;
}
/* Make sure bus domain is awake */
ret = power_domain_on(&priv->pd_bus);
if (ret)
return ret;
/* Put devices into reset */
clrbits_le32(priv->base + BLK_SFT_RSTN, reset);
/* Enable upstream clocks */
ret = clk_enable(&priv->clk_apb);
if (ret)
goto dis_bus_pd;
ret = clk_enable(&priv->clk_axi);
if (ret)
goto dis_apb_clk;
/* Enable blk-ctrl clock to allow reset to propagate */
ret = clk_enable(clk);
if (ret)
goto dis_axi_clk;
setbits_le32(priv->base + BLK_CLK_EN, reset);
/* Power up upstream GPC domain */
ret = power_domain_on(domain);
if (ret)
goto dis_lcdif_clk;
/* Wait for reset to propagate */
udelay(5);
/* Release reset */
setbits_le32(priv->base + BLK_SFT_RSTN, reset);
return 0;
dis_lcdif_clk:
clk_disable(clk);
dis_axi_clk:
clk_disable(&priv->clk_axi);
dis_apb_clk:
clk_disable(&priv->clk_apb);
dis_bus_pd:
power_domain_off(&priv->pd_bus);
return ret;
}
static int imx8mp_mediamix_off(struct power_domain *power_domain)
{
struct udevice *dev = power_domain->dev;
struct imx8mp_mediamix_priv *priv = dev_get_priv(dev);
struct power_domain *domain;
struct clk *clk;
u32 reset;
switch (power_domain->id) {
case IMX8MP_MEDIABLK_PD_LCDIF_2:
domain = &priv->pd_lcdif2;
clk = &priv->clk_disp2;
reset = BIT(11) | BIT(12) | BIT(24);
break;
default:
return -EINVAL;
}
/* Put devices into reset and disable clocks */
clrbits_le32(priv->base + BLK_SFT_RSTN, reset);
clrbits_le32(priv->base + BLK_CLK_EN, reset);
/* Power down upstream GPC domain */
power_domain_off(domain);
clk_disable(clk);
clk_disable(&priv->clk_axi);
clk_disable(&priv->clk_apb);
/* Allow bus domain to suspend */
power_domain_off(&priv->pd_bus);
return 0;
}
static int imx8mp_mediamix_of_xlate(struct power_domain *power_domain,
struct ofnode_phandle_args *args)
{
power_domain->id = args->args[0];
return 0;
}
static int imx8mp_mediamix_bind(struct udevice *dev)
{
/* Bind child lcdif */
return dm_scan_fdt_dev(dev);
}
static int imx8mp_mediamix_probe(struct udevice *dev)
{
struct imx8mp_mediamix_priv *priv = dev_get_priv(dev);
int ret;
priv->base = dev_read_addr_ptr(dev);
ret = clk_get_by_name(dev, "apb", &priv->clk_apb);
if (ret < 0)
return ret;
ret = clk_get_by_name(dev, "axi", &priv->clk_axi);
if (ret < 0)
return ret;
ret = clk_get_by_name(dev, "disp2", &priv->clk_disp2);
if (ret < 0)
return ret;
ret = power_domain_get_by_name(dev, &priv->pd_bus, "bus");
if (ret < 0)
return ret;
ret = power_domain_get_by_name(dev, &priv->pd_lcdif2, "lcdif2");
if (ret < 0)
goto free_bus_pd;
return 0;
free_bus_pd:
power_domain_free(&priv->pd_bus);
return ret;
}
static int imx8mp_mediamix_remove(struct udevice *dev)
{
struct imx8mp_mediamix_priv *priv = dev_get_priv(dev);
power_domain_free(&priv->pd_lcdif2);
power_domain_free(&priv->pd_bus);
return 0;
}
static const struct udevice_id imx8mp_mediamix_ids[] = {
{ .compatible = "fsl,imx8mp-media-blk-ctrl" },
{ }
};
struct power_domain_ops imx8mp_mediamix_ops = {
.on = imx8mp_mediamix_on,
.off = imx8mp_mediamix_off,
.of_xlate = imx8mp_mediamix_of_xlate,
};
U_BOOT_DRIVER(imx8mp_mediamix) = {
.name = "imx8mp_mediamix",
.id = UCLASS_POWER_DOMAIN,
.of_match = imx8mp_mediamix_ids,
.bind = imx8mp_mediamix_bind,
.probe = imx8mp_mediamix_probe,
.remove = imx8mp_mediamix_remove,
.priv_auto = sizeof(struct imx8mp_mediamix_priv),
.ops = &imx8mp_mediamix_ops,
};

View File

@@ -12,6 +12,10 @@
#include <power-domain-uclass.h>
#include <dm/device-internal.h>
struct power_domain_priv {
int on_count;
};
static inline struct power_domain_ops *power_domain_dev_ops(struct udevice *dev)
{
return (struct power_domain_ops *)dev->driver->ops;
@@ -107,22 +111,49 @@ int power_domain_free(struct power_domain *power_domain)
return ops->rfree ? ops->rfree(power_domain) : 0;
}
int power_domain_on(struct power_domain *power_domain)
int power_domain_on_lowlevel(struct power_domain *power_domain)
{
struct power_domain_priv *priv = dev_get_uclass_priv(power_domain->dev);
struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
int ret;
debug("%s(power_domain=%p)\n", __func__, power_domain);
return ops->on ? ops->on(power_domain) : 0;
if (priv->on_count++ > 0)
return -EALREADY;
ret = ops->on ? ops->on(power_domain) : 0;
if (ret) {
priv->on_count--;
return ret;
}
return 0;
}
int power_domain_off(struct power_domain *power_domain)
int power_domain_off_lowlevel(struct power_domain *power_domain)
{
struct power_domain_priv *priv = dev_get_uclass_priv(power_domain->dev);
struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
int ret;
debug("%s(power_domain=%p)\n", __func__, power_domain);
return ops->off ? ops->off(power_domain) : 0;
if (priv->on_count <= 0) {
debug("Power domain %s already off.\n", power_domain->dev->name);
return -EALREADY;
}
if (priv->on_count-- > 1)
return -EBUSY;
ret = ops->off ? ops->off(power_domain) : 0;
if (ret) {
priv->on_count++;
return ret;
}
return 0;
}
#if CONFIG_IS_ENABLED(OF_REAL)
@@ -180,4 +211,5 @@ int dev_power_domain_off(struct udevice *dev)
UCLASS_DRIVER(power_domain) = {
.id = UCLASS_POWER_DOMAIN,
.name = "power_domain",
.per_device_auto = sizeof(struct power_domain_priv),
};

View File

@@ -51,4 +51,5 @@ U_BOOT_DRIVER(sandbox_power_domain_test) = {
.id = UCLASS_MISC,
.of_match = sandbox_power_domain_test_ids,
.priv_auto = sizeof(struct sandbox_power_domain_test),
.flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
};

View File

@@ -53,7 +53,7 @@ obj-$(CONFIG_VIDEO_COREBOOT) += coreboot.o
obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
obj-$(CONFIG_VIDEO_DW_MIPI_DSI) += dw_mipi_dsi.o
obj-$(CONFIG_VIDEO_EFI) += efi.o
obj-$(CONFIG_VIDEO_IPUV3) += imx/
obj-y += imx/
obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o
obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o
obj-$(CONFIG_VIDEO_LCD_ENDEAVORU) += endeavoru-panel.o

View File

@@ -13,3 +13,12 @@ config IMX_VIDEO_SKIP
config IMX_HDMI
bool "Enable HDMI support in IPUv3"
depends on VIDEO_IPUV3
config IMX_LDB
bool "Freescale i.MX8MP LDB bridge"
depends on VIDEO_BRIDGE
help
Support for i.MX8MP DPI-to-LVDS on-SoC encoder.
config IMX_LCDIF
bool "i.MX LCDIFv3 LCD controller"

View File

@@ -3,4 +3,6 @@
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-y += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
obj-$(CONFIG_IMX_LDB) += ldb.o
obj-$(CONFIG_IMX_LCDIF) += lcdif.o

314
drivers/video/imx/lcdif.c Normal file
View File

@@ -0,0 +1,314 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* i.MX8 LCD interface driver inspired from the Linux driver
* Copyright 2019 NXP
* Copyright 2024 Bootlin
* Adapted by Miquel Raynal <miquel.raynal@bootlin.com>
*/
#include <asm/io.h>
#include <asm/mach-imx/dma.h>
#include <clk.h>
#include <dm.h>
#include <panel.h>
#include <power-domain.h>
#include <video.h>
#include <video_bridge.h>
#include <linux/delay.h>
#include "../videomodes.h"
#define LCDIFV3_CTRL 0x0
#define LCDIFV3_CTRL_SET 0x4
#define LCDIFV3_CTRL_CLR 0x8
#define CTRL_INV_HS BIT(0)
#define CTRL_INV_VS BIT(1)
#define CTRL_INV_DE BIT(2)
#define CTRL_INV_PXCK BIT(3)
#define CTRL_CLK_GATE BIT(30)
#define CTRL_SW_RESET BIT(31)
#define LCDIFV3_DISP_PARA 0x10
#define DISP_PARA_DISP_MODE_NORMAL 0
#define DISP_PARA_LINE_PATTERN_RGB_YUV 0
#define DISP_PARA_DISP_ON BIT(31)
#define LCDIFV3_DISP_SIZE 0x14
#define DISP_SIZE_DELTA_X(x) ((x) & 0xffff)
#define DISP_SIZE_DELTA_Y(x) ((x) << 16)
#define LCDIFV3_HSYN_PARA 0x18
#define HSYN_PARA_FP_H(x) ((x) & 0xffff)
#define HSYN_PARA_BP_H(x) ((x) << 16)
#define LCDIFV3_VSYN_PARA 0x1C
#define VSYN_PARA_FP_V(x) ((x) & 0xffff)
#define VSYN_PARA_BP_V(x) ((x) << 16)
#define LCDIFV3_VSYN_HSYN_WIDTH 0x20
#define VSYN_HSYN_PW_H(x) ((x) & 0xffff)
#define VSYN_HSYN_PW_V(x) ((x) << 16)
#define LCDIFV3_CTRLDESCL0_1 0x200
#define CTRLDESCL0_1_WIDTH(x) ((x) & 0xffff)
#define CTRLDESCL0_1_HEIGHT(x) ((x) << 16)
#define LCDIFV3_CTRLDESCL0_3 0x208
#define CTRLDESCL0_3_PITCH(x) ((x) & 0xFFFF)
#define LCDIFV3_CTRLDESCL_LOW0_4 0x20C
#define LCDIFV3_CTRLDESCL_HIGH0_4 0x210
#define LCDIFV3_CTRLDESCL0_5 0x214
#define CTRLDESCL0_5_YUV_FORMAT(x) (((x) & 0x3) << 14)
#define CTRLDESCL0_5_BPP(x) (((x) & 0xf) << 24)
#define BPP32_ARGB8888 0x9
#define CTRLDESCL0_5_SHADOW_LOAD_EN BIT(30)
#define CTRLDESCL0_5_EN BIT(31)
struct lcdifv3_priv {
void __iomem *base;
struct clk pix_clk;
struct power_domain pd;
struct udevice *panel;
struct udevice *bridge;
};
static void lcdifv3_set_mode(struct lcdifv3_priv *priv,
struct display_timing *timings)
{
u32 reg;
writel(DISP_SIZE_DELTA_X(timings->hactive.typ) |
DISP_SIZE_DELTA_Y(timings->vactive.typ),
priv->base + LCDIFV3_DISP_SIZE);
writel(HSYN_PARA_FP_H(timings->hfront_porch.typ) |
HSYN_PARA_BP_H(timings->hback_porch.typ),
priv->base + LCDIFV3_HSYN_PARA);
writel(VSYN_PARA_BP_V(timings->vback_porch.typ) |
VSYN_PARA_FP_V(timings->vfront_porch.typ),
priv->base + LCDIFV3_VSYN_PARA);
writel(VSYN_HSYN_PW_H(timings->hsync_len.typ) |
VSYN_HSYN_PW_V(timings->vsync_len.typ),
priv->base + LCDIFV3_VSYN_HSYN_WIDTH);
writel(CTRLDESCL0_1_WIDTH(timings->hactive.typ) |
CTRLDESCL0_1_HEIGHT(timings->vactive.typ),
priv->base + LCDIFV3_CTRLDESCL0_1);
if (timings->flags & DISPLAY_FLAGS_HSYNC_LOW)
writel(CTRL_INV_HS, priv->base + LCDIFV3_CTRL_SET);
else
writel(CTRL_INV_HS, priv->base + LCDIFV3_CTRL_CLR);
if (timings->flags & DISPLAY_FLAGS_VSYNC_LOW)
writel(CTRL_INV_VS, priv->base + LCDIFV3_CTRL_SET);
else
writel(CTRL_INV_VS, priv->base + LCDIFV3_CTRL_CLR);
if (timings->flags & DISPLAY_FLAGS_DE_LOW)
writel(CTRL_INV_DE, priv->base + LCDIFV3_CTRL_SET);
else
writel(CTRL_INV_DE, priv->base + LCDIFV3_CTRL_CLR);
if (timings->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
writel(CTRL_INV_PXCK, priv->base + LCDIFV3_CTRL_SET);
else
writel(CTRL_INV_PXCK, priv->base + LCDIFV3_CTRL_CLR);
writel(0, priv->base + LCDIFV3_DISP_PARA);
reg = readl(priv->base + LCDIFV3_CTRLDESCL0_5);
reg &= ~(CTRLDESCL0_5_BPP(0xf) | CTRLDESCL0_5_YUV_FORMAT(0x3));
reg |= CTRLDESCL0_5_BPP(BPP32_ARGB8888);
writel(reg, priv->base + LCDIFV3_CTRLDESCL0_5);
}
static void lcdifv3_enable_controller(struct lcdifv3_priv *priv)
{
u32 reg;
reg = readl(priv->base + LCDIFV3_DISP_PARA);
reg |= DISP_PARA_DISP_ON;
writel(reg, priv->base + LCDIFV3_DISP_PARA);
reg = readl(priv->base + LCDIFV3_CTRLDESCL0_5);
reg |= CTRLDESCL0_5_EN;
writel(reg, priv->base + LCDIFV3_CTRLDESCL0_5);
}
static int lcdifv3_video_sync(struct udevice *dev)
{
struct lcdifv3_priv *priv = dev_get_priv(dev);
u32 reg;
reg = readl(priv->base + LCDIFV3_CTRLDESCL0_5);
reg |= CTRLDESCL0_5_SHADOW_LOAD_EN;
writel(reg, priv->base + LCDIFV3_CTRLDESCL0_5);
return 0;
}
static void lcdifv3_init(struct udevice *dev, struct display_timing *timings)
{
struct video_uc_plat *plat = dev_get_uclass_plat(dev);
struct lcdifv3_priv *priv = dev_get_priv(dev);
clk_set_rate(&priv->pix_clk, timings->pixelclock.typ);
writel(CTRL_SW_RESET | CTRL_CLK_GATE, priv->base + LCDIFV3_CTRL_CLR);
udelay(10);
lcdifv3_set_mode(priv, timings);
writel(plat->base & 0xFFFFFFFF, priv->base + LCDIFV3_CTRLDESCL_LOW0_4);
writel(plat->base >> 32, priv->base + LCDIFV3_CTRLDESCL_HIGH0_4);
writel(CTRLDESCL0_3_PITCH(timings->hactive.typ * 4), /* 32bpp */
priv->base + LCDIFV3_CTRLDESCL0_3);
lcdifv3_enable_controller(priv);
}
static int lcdifv3_video_probe(struct udevice *dev)
{
struct video_uc_plat *plat = dev_get_uclass_plat(dev);
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
struct lcdifv3_priv *priv = dev_get_priv(dev);
struct clk axi_clk, disp_axi_clk;
struct display_timing timings;
u32 fb_start, fb_end;
int ret;
ret = power_domain_get(dev, &priv->pd);
if (ret < 0)
return ret;
ret = clk_get_by_name(dev, "pix", &priv->pix_clk);
if (ret < 0)
return ret;
ret = clk_get_by_name(dev, "axi", &axi_clk);
if (ret < 0)
return ret;
ret = clk_get_by_name(dev, "disp_axi", &disp_axi_clk);
if (ret < 0)
return ret;
ret = power_domain_on(&priv->pd);
if (ret)
return ret;
ret = clk_enable(&priv->pix_clk);
if (ret)
goto dis_pd;
ret = clk_enable(&axi_clk);
if (ret)
goto dis_pix_clk;
ret = clk_enable(&disp_axi_clk);
if (ret)
goto dis_axi_clk;
priv->base = dev_remap_addr(dev);
if (!priv->base) {
ret = -EINVAL;
goto dis_clks;
}
/* Attach bridge */
ret = uclass_get_device_by_endpoint(UCLASS_VIDEO_BRIDGE, dev,
-1, -1, &priv->bridge);
if (ret)
goto dis_clks;
ret = video_bridge_attach(priv->bridge);
if (ret)
goto dis_clks;
ret = video_bridge_set_backlight(priv->bridge, 80);
if (ret)
goto dis_clks;
/* Attach panels */
ret = uclass_get_device_by_endpoint(UCLASS_PANEL, priv->bridge,
1, -1, &priv->panel);
if (ret) {
ret = uclass_get_device_by_endpoint(UCLASS_PANEL, priv->bridge,
2, -1, &priv->panel);
if (ret)
goto dis_clks;
}
ret = panel_get_display_timing(priv->panel, &timings);
if (ret) {
ret = ofnode_decode_display_timing(dev_ofnode(priv->panel),
0, &timings);
if (ret) {
printf("Cannot decode panel timings (%d)\n", ret);
goto dis_clks;
}
}
lcdifv3_init(dev, &timings);
/* Only support 32bpp for now */
uc_priv->bpix = VIDEO_BPP32;
uc_priv->xsize = timings.hactive.typ;
uc_priv->ysize = timings.vactive.typ;
/* Enable dcache for the frame buffer */
fb_start = plat->base & ~(MMU_SECTION_SIZE - 1);
fb_end = ALIGN(plat->base + plat->size, 1 << MMU_SECTION_SHIFT);
mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
DCACHE_WRITEBACK);
video_set_flush_dcache(dev, true);
return 0;
dis_clks:
clk_disable(&disp_axi_clk);
dis_axi_clk:
clk_disable(&axi_clk);
dis_pix_clk:
clk_disable(&priv->pix_clk);
dis_pd:
power_domain_off(&priv->pd);
return ret;
}
static int lcdifv3_video_bind(struct udevice *dev)
{
struct video_uc_plat *plat = dev_get_uclass_plat(dev);
/* Max size supported by LCDIF */
plat->size = 1920 * 1080 * VNBYTES(VIDEO_BPP32);
return 0;
}
static const struct udevice_id lcdifv3_video_ids[] = {
{ .compatible = "fsl,imx8mp-lcdif" },
{ }
};
static struct video_ops lcdifv3_video_ops = {
.video_sync = lcdifv3_video_sync,
};
U_BOOT_DRIVER(lcdifv3_video) = {
.name = "lcdif",
.id = UCLASS_VIDEO,
.of_match = lcdifv3_video_ids,
.bind = lcdifv3_video_bind,
.ops = &lcdifv3_video_ops,
.probe = lcdifv3_video_probe,
.priv_auto = sizeof(struct lcdifv3_priv),
.flags = DM_FLAG_PRE_RELOC | DM_FLAG_OS_PREPARE,
};

251
drivers/video/imx/ldb.c Normal file
View File

@@ -0,0 +1,251 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Derived work from:
* Philippe Cornu <philippe.cornu@st.com>
* Yannick Fertre <yannick.fertre@st.com>
* Adapted by Miquel Raynal <miquel.raynal@bootlin.com>
*/
#define LOG_CATEGORY UCLASS_VIDEO_BRIDGE
#include <clk.h>
#include <dm.h>
#include <log.h>
#include <panel.h>
#include <video_bridge.h>
#include <asm/io.h>
#include <linux/delay.h>
#define LDB_CTRL_CH0_ENABLE BIT(0)
#define LDB_CTRL_CH1_ENABLE BIT(2)
#define LDB_CTRL_CH0_DATA_WIDTH BIT(5)
#define LDB_CTRL_CH0_BIT_MAPPING BIT(6)
#define LDB_CTRL_CH1_DATA_WIDTH BIT(7)
#define LDB_CTRL_CH1_BIT_MAPPING BIT(8)
#define LDB_CTRL_DI0_VSYNC_POLARITY BIT(9)
#define LDB_CTRL_DI1_VSYNC_POLARITY BIT(10)
#define LVDS_CTRL_CH0_EN BIT(0)
#define LVDS_CTRL_CH1_EN BIT(1)
#define LVDS_CTRL_VBG_EN BIT(2)
#define LVDS_CTRL_PRE_EMPH_EN BIT(4)
#define LVDS_CTRL_PRE_EMPH_ADJ(n) (((n) & 0x7) << 5)
#define LVDS_CTRL_CC_ADJ(n) (((n) & 0x7) << 11)
struct imx_ldb_priv {
struct clk ldb_clk;
void __iomem *ldb_ctrl;
void __iomem *lvds_ctrl;
struct udevice *lvds1;
struct udevice *lvds2;
};
static int imx_ldb_set_backlight(struct udevice *dev, int percent)
{
struct imx_ldb_priv *priv = dev_get_priv(dev);
int ret;
if (priv->lvds1) {
ret = panel_enable_backlight(priv->lvds1);
if (ret) {
debug("ldb: Cannot enable lvds1 backlight\n");
return ret;
}
ret = panel_set_backlight(priv->lvds1, percent);
if (ret)
return ret;
}
if (priv->lvds2) {
ret = panel_enable_backlight(priv->lvds2);
if (ret) {
debug("ldb: Cannot enable lvds2 backlight\n");
return ret;
}
ret = panel_set_backlight(priv->lvds2, percent);
if (ret)
return ret;
}
return 0;
}
static int imx_ldb_of_to_plat(struct udevice *dev)
{
struct imx_ldb_priv *priv = dev_get_priv(dev);
int ret;
uclass_get_device_by_endpoint(UCLASS_PANEL, dev, 1, -1, &priv->lvds1);
uclass_get_device_by_endpoint(UCLASS_PANEL, dev, 2, -1, &priv->lvds2);
if (!priv->lvds1 && !priv->lvds2) {
debug("ldb: No remote panel for '%s' (ret=%d)\n",
dev_read_name(dev), ret);
return ret;
}
return 0;
}
/* The block has a mysterious x7 internal divisor (x3.5 in dual configuration) */
#define IMX_LDB_INTERNAL_DIVISOR(x) (((x) * 70) / 10)
#define IMX_LDB_INTERNAL_DIVISOR_DUAL(x) (((x) * 35) / 10)
static ulong imx_ldb_input_rate(struct imx_ldb_priv *priv,
struct display_timing *timings)
{
ulong target_rate = timings->pixelclock.typ;
if (priv->lvds1 && priv->lvds2)
return IMX_LDB_INTERNAL_DIVISOR_DUAL(target_rate);
return IMX_LDB_INTERNAL_DIVISOR(target_rate);
}
static int imx_ldb_attach(struct udevice *dev)
{
struct imx_ldb_priv *priv = dev_get_priv(dev);
struct display_timing timings;
bool format_jeida = false;
bool format_24bpp = true;
u32 ldb_ctrl = 0, lvds_ctrl;
ulong ldb_rate;
int ret;
/* TODO: update the 24bpp/jeida booleans with proper checks when they
* will be supported.
*/
if (priv->lvds1) {
ret = panel_get_display_timing(priv->lvds1, &timings);
if (ret) {
ret = ofnode_decode_display_timing(dev_ofnode(priv->lvds1),
0, &timings);
if (ret) {
printf("Cannot decode lvds1 timings (%d)\n", ret);
return ret;
}
}
ldb_ctrl |= LDB_CTRL_CH0_ENABLE;
if (format_24bpp)
ldb_ctrl |= LDB_CTRL_CH0_DATA_WIDTH;
if (format_jeida)
ldb_ctrl |= LDB_CTRL_CH0_BIT_MAPPING;
if (timings.flags & DISPLAY_FLAGS_VSYNC_HIGH)
ldb_ctrl |= LDB_CTRL_DI0_VSYNC_POLARITY;
}
if (priv->lvds2) {
ret = panel_get_display_timing(priv->lvds2, &timings);
if (ret) {
ret = ofnode_decode_display_timing(dev_ofnode(priv->lvds2),
0, &timings);
if (ret) {
printf("Cannot decode lvds2 timings (%d)\n", ret);
return ret;
}
}
ldb_ctrl |= LDB_CTRL_CH1_ENABLE;
if (format_24bpp)
ldb_ctrl |= LDB_CTRL_CH1_DATA_WIDTH;
if (format_jeida)
ldb_ctrl |= LDB_CTRL_CH1_BIT_MAPPING;
if (timings.flags & DISPLAY_FLAGS_VSYNC_HIGH)
ldb_ctrl |= LDB_CTRL_DI1_VSYNC_POLARITY;
}
/*
* Not all pixel clocks will work, as the final rate (after internal
* integer division) should be identical to the LCDIF clock, otherwise
* the rendering will appear resized/shimmering.
*/
ldb_rate = imx_ldb_input_rate(priv, &timings);
clk_set_rate(&priv->ldb_clk, ldb_rate);
writel(ldb_ctrl, priv->ldb_ctrl);
lvds_ctrl = LVDS_CTRL_CC_ADJ(2) | LVDS_CTRL_PRE_EMPH_EN |
LVDS_CTRL_PRE_EMPH_ADJ(3) | LVDS_CTRL_VBG_EN;
writel(lvds_ctrl, priv->lvds_ctrl);
/* Wait for VBG to stabilize. */
udelay(15);
if (priv->lvds1)
lvds_ctrl |= LVDS_CTRL_CH0_EN;
if (priv->lvds2)
lvds_ctrl |= LVDS_CTRL_CH1_EN;
writel(lvds_ctrl, priv->lvds_ctrl);
return 0;
}
static int imx_ldb_probe(struct udevice *dev)
{
struct imx_ldb_priv *priv = dev_get_priv(dev);
struct udevice *parent = dev_get_parent(dev);
fdt_addr_t parent_addr, child_addr;
int ret;
ret = clk_get_by_name(dev, "ldb", &priv->ldb_clk);
if (ret < 0)
return ret;
parent_addr = dev_read_addr(parent);
if (parent_addr == FDT_ADDR_T_NONE)
return -EINVAL;
child_addr = dev_read_addr_name(dev, "ldb");
if (child_addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->ldb_ctrl = map_physmem(parent_addr + child_addr, 0, MAP_NOCACHE);
if (!priv->ldb_ctrl)
return -EINVAL;
child_addr = dev_read_addr_name(dev, "lvds");
if (child_addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->lvds_ctrl = map_physmem(parent_addr + child_addr, 0, MAP_NOCACHE);
if (!priv->lvds_ctrl)
return -EINVAL;
ret = clk_enable(&priv->ldb_clk);
if (ret)
return ret;
ret = video_bridge_set_active(dev, true);
if (ret)
goto dis_clk;
return 0;
dis_clk:
clk_disable(&priv->ldb_clk);
return ret;
}
struct video_bridge_ops imx_ldb_ops = {
.attach = imx_ldb_attach,
.set_backlight = imx_ldb_set_backlight,
};
static const struct udevice_id imx_ldb_ids[] = {
{ .compatible = "fsl,imx8mp-ldb"},
{ }
};
U_BOOT_DRIVER(imx_ldb) = {
.name = "imx-lvds-display-bridge",
.id = UCLASS_VIDEO_BRIDGE,
.of_match = imx_ldb_ids,
.probe = imx_ldb_probe,
.of_to_plat = imx_ldb_of_to_plat,
.ops = &imx_ldb_ops,
.priv_auto = sizeof(struct imx_ldb_priv),
};

View File

@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2024 Toradex */
#ifndef __TORADEX_SMARC_IMX8MP_H
#define __TORADEX_SMARC_IMX8MP_H
#include <asm/arch/imx-regs.h>
#include <linux/sizes.h>
#define CFG_SYS_UBOOT_BASE \
(QSPI0_AMBA_BASE + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR * 512)
#ifdef CONFIG_SPL_BUILD
/* malloc f used before GD_FLG_FULL_MALLOC_INIT set */
#define CFG_MALLOC_F_ADDR 0x184000
#endif /* CONFIG_SPL_BUILD */
#define CFG_SYS_INIT_RAM_ADDR 0x40000000
#define CFG_SYS_INIT_RAM_SIZE SZ_512K
/* i.MX 8M Plus supports max. 8GB memory in two albeit consecutive banks */
#define CFG_SYS_SDRAM_BASE 0x40000000
#define PHYS_SDRAM 0x40000000
#define PHYS_SDRAM_SIZE (SZ_2G + SZ_1G)
#define PHYS_SDRAM_2 0x100000000
#define PHYS_SDRAM_2_SIZE (SZ_4G + SZ_1G)
#endif /* __TORADEX_SMARC_IMX8MP_H */

View File

@@ -333,6 +333,30 @@ int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
int uclass_get_device_by_driver(enum uclass_id id, const struct driver *drv,
struct udevice **devp);
/**
* uclass_get_device_by_endpoint() - Get a uclass device for a remote endpoint
*
* This searches through the parents of the specified remote endpoint
* for the first device matching the uclass. Said otherwise, this helper
* goes through the graph (endpoint) representation and searches for
* matching devices. Endpoints can be subnodes of the "port" node or
* subnodes of ports identified with a reg property, themselves in a
* "ports" container.
*
* The device is probed to activate it ready for use.
*
* @class_id: uclass ID to look up
* @dev: Device to start from
* @port_idx: Index of the port to follow, -1 if there is a single 'port'
* node without reg.
* @ep_idx: Index of the endpoint to follow, -1 if there is a single 'endpoint'
* node without reg.
* @target: Returns pointer to the first device matching the expected uclass.
* Return: 0 if OK, -ve on error
*/
int uclass_get_device_by_endpoint(enum uclass_id class_id, struct udevice *dev,
int port_idx, int ep_idx, struct udevice **target);
/**
* uclass_first_device() - Get the first device in a uclass
*

View File

@@ -147,37 +147,81 @@ static inline int power_domain_free(struct power_domain *power_domain)
#endif
/**
* power_domain_on - Enable power to a power domain.
* power_domain_on_lowlevel - Enable power to a power domain (with refcounting)
*
* @power_domain: A power domain struct that was previously successfully
* requested by power_domain_get().
* Return: 0 if OK, or a negative error code.
* Return: 0 if the transition has been performed correctly,
* -EALREADY if the domain is already on,
* a negative error code otherwise.
*/
#if CONFIG_IS_ENABLED(POWER_DOMAIN)
int power_domain_on(struct power_domain *power_domain);
int power_domain_on_lowlevel(struct power_domain *power_domain);
#else
static inline int power_domain_on(struct power_domain *power_domain)
static inline int power_domain_on_lowlevel(struct power_domain *power_domain)
{
return -ENOSYS;
}
#endif
/**
* power_domain_off - Disable power to a power domain.
* power_domain_on - Enable power to a power domain (ignores the actual state
* of the power domain)
*
* @power_domain: A power domain struct that was previously successfully
* requested by power_domain_get().
* Return: 0 if OK, or a negative error code.
* Return: a negative error code upon error during the transition, 0 otherwise.
*/
static inline int power_domain_on(struct power_domain *power_domain)
{
int ret;
ret = power_domain_on_lowlevel(power_domain);
if (ret == -EALREADY)
ret = 0;
return ret;
}
/**
* power_domain_off_lowlevel - Disable power to a power domain (with refcounting)
*
* @power_domain: A power domain struct that was previously successfully
* requested by power_domain_get().
* Return: 0 if the transition has been performed correctly,
* -EALREADY if the domain is already off,
* -EBUSY if another device is keeping the domain on (but the refcounter
* is decremented),
* a negative error code otherwise.
*/
#if CONFIG_IS_ENABLED(POWER_DOMAIN)
int power_domain_off(struct power_domain *power_domain);
int power_domain_off_lowlevel(struct power_domain *power_domain);
#else
static inline int power_domain_off(struct power_domain *power_domain)
static inline int power_domain_off_lowlevel(struct power_domain *power_domain)
{
return -ENOSYS;
}
#endif
/**
* power_domain_off - Disable power to a power domain (ignores the actual state
* of the power domain)
*
* @power_domain: A power domain struct that was previously successfully
* requested by power_domain_get().
* Return: a negative error code upon error during the transition, 0 otherwise.
*/
static inline int power_domain_off(struct power_domain *power_domain)
{
int ret;
ret = power_domain_off_lowlevel(power_domain);
if (ret == -EALREADY || ret == -EBUSY)
ret = 0;
return ret;
}
/**
* dev_power_domain_on - Enable power domains for a device .
*

View File

@@ -27,7 +27,7 @@ static int dm_test_power_domain(struct unit_test_state *uts)
ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "power-domain-test",
&dev_test));
ut_asserteq(1, sandbox_power_domain_query(dev_power_domain,
ut_asserteq(0, sandbox_power_domain_query(dev_power_domain,
TEST_POWER_DOMAIN));
ut_assertok(sandbox_power_domain_test_get(dev_test));

View File

@@ -792,7 +792,7 @@ DM_TEST(dm_test_fdt_disable_enable_by_path, UTF_SCAN_PDATA | UTF_SCAN_FDT);
/* Test a few uclass phandle functions */
static int dm_test_fdt_phandle(struct unit_test_state *uts)
{
struct udevice *back, *dev, *dev2;
struct udevice *back, *dispc, *panel, *dev, *dev2;
ut_assertok(uclass_find_first_device(UCLASS_PANEL_BACKLIGHT, &back));
ut_assertnonnull(back);
@@ -807,6 +807,24 @@ static int dm_test_fdt_phandle(struct unit_test_state *uts)
"power-supply", &dev2));
ut_asserteq_ptr(dev, dev2);
/* Test uclass_get_device_by_endpoint() */
ut_assertok(uclass_find_device_by_name(UCLASS_VIDEO_BRIDGE, "lvds-encoder", &dispc));
ut_assertnonnull(dispc);
ut_asserteq(0, device_active(dispc));
ut_assertok(uclass_find_device_by_name(UCLASS_PANEL, "panel", &panel));
ut_assertnonnull(panel);
ut_asserteq(0, device_active(panel));
ut_asserteq(-ENODEV, uclass_get_device_by_endpoint(UCLASS_PANEL_BACKLIGHT, dispc, 1, -1, &dev));
ut_asserteq(-EINVAL, uclass_get_device_by_endpoint(UCLASS_PANEL, dispc, 0, -1, &dev));
ut_assertok(uclass_get_device_by_endpoint(UCLASS_PANEL, dispc, 1, -1, &dev));
ut_asserteq_ptr(panel, dev);
ut_asserteq(-ENODEV, uclass_get_device_by_endpoint(UCLASS_PANEL_BACKLIGHT, panel, -1, -1, &dev2));
ut_asserteq(-EINVAL, uclass_get_device_by_endpoint(UCLASS_VIDEO_BRIDGE, panel, 1, -1, &dev2));
ut_assertok(uclass_get_device_by_endpoint(UCLASS_VIDEO_BRIDGE, panel, -1, -1, &dev2));
ut_asserteq_ptr(dispc, dev2);
return 0;
}
DM_TEST(dm_test_fdt_phandle, UTF_SCAN_PDATA | UTF_SCAN_FDT);