* Re: [PATCH v14, 2/2] net: Add dm9051 driver
From: Jakub Kicinski @ 2022-01-28 1:57 UTC (permalink / raw)
To: Joseph CHAMG
Cc: David S . Miller, Rob Herring, joseph_chang, netdev, devicetree,
linux-kernel, andy.shevchenko, andrew, leon
In-Reply-To: <20220127032701.23056-3-josright123@gmail.com>
On Thu, 27 Jan 2022 11:27:01 +0800 Joseph CHAMG wrote:
> Add davicom dm9051 spi ethernet driver, The driver work for the
> device platform which has the spi master
>
> Signed-off-by: Joseph CHAMG <josright123@gmail.com>
> +/* event: write into the mac registers and eeprom directly
> + */
> +static int dm9051_set_mac_address(struct net_device *ndev, void *p)
> +{
> + struct board_info *db = to_dm9051_board(ndev);
> + int ret;
> +
> + ret = eth_mac_addr(ndev, p);
You should not be using this helper if the write can fail. See what
this function does internally and:
- put the eth_prepare_mac_addr_change() call here
> + if (ret < 0)
> + return ret;
> +
> + ret = regmap_bulk_write(db->regmap_dmbulk, DM9051_PAR, ndev->dev_addr, ETH_ALEN);
> + if (ret < 0)
> + netif_err(db, drv, ndev, "%s: error %d bulk writing reg %02x, len %d\n",
> + __func__, ret, DM9051_PAR, ETH_ALEN);
- put the eth_commit_mac_addr_change() call here
> + return ret;
> +}
> +static void dm9051_netdev(struct net_device *ndev)
> +{
> + ndev->mtu = 1500;
Unnecessary, ether_setup() does this already.
> + ndev->if_port = IF_PORT_100BASET;
Why set this? The if_port API is a leftover from very old 10Mbit
Ethernet days, we have ethtool link APIs now.
> + ndev->netdev_ops = &dm9051_netdev_ops;
> + ndev->ethtool_ops = &dm9051_ethtool_ops;
Just inline there two lines into the caller and remove the helper.
dm9051_netdev() does not sound like a function that does setup.
> +}
> +
> +static int dm9051_map_init(struct spi_device *spi, struct board_info *db)
> +{
> + /* create two regmap instances,
> + * run read/write and bulk_read/bulk_write individually,
> + * to resolve regmap execution confliction problem
> + */
> + regconfigdm.lock_arg = db;
> + db->regmap_dm = devm_regmap_init_spi(db->spidev, ®configdm);
> +
> + if (IS_ERR(db->regmap_dm))
> + return PTR_ERR_OR_ZERO(db->regmap_dm);
> +
> + regconfigdmbulk.lock_arg = db;
> + db->regmap_dmbulk = devm_regmap_init_spi(db->spidev, ®configdmbulk);
> +
Please remove all the empty lines between function call and error
checking the result.
> + if (IS_ERR(db->regmap_dmbulk))
> + return PTR_ERR_OR_ZERO(db->regmap_dmbulk);
Why _OR_ZERO() when you're in a IS_ERR() condition already?
> + return 0;
> + ret = devm_register_netdev(dev, ndev);
> + if (ret) {
> + dev_err(dev, "failed to register network device\n");
> + kthread_stop(db->kwr_task_kw);
> + phy_disconnect(db->phydev);
> + return ret;
> + }
> +
> + skb_queue_head_init(&db->txq);
All the state must be initialized before netdev is registered,
otherwise another thread may immediately open the device and
start to transmit.
> + return 0;
> +
> +err_stopthread:
> + kthread_stop(db->kwr_task_kw);
> + return ret;
> +}
^ permalink raw reply
* [PATCH v2] arm64: dts: imx8m{m,n}_venice*: add gpio-line-names
From: Tim Harvey @ 2022-01-28 1:06 UTC (permalink / raw)
To: Rob Herring, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, NXP Linux Team, devicetree, linux-kernel,
linux-arm-kernel
Cc: Tim Harvey
Add gpio-line-names for the various GPIO's used on Gateworks Venice
boards. Note that these GPIO's are typically 'configured' in Boot
Firmware via gpio-hog therefore we only configure line names to keep the
boot firmware configuration from changing on kernel init.
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
v2: rebase on imx/dt64
---
.../dts/freescale/imx8mm-venice-gw71xx.dtsi | 14 +++++++
.../dts/freescale/imx8mm-venice-gw72xx.dtsi | 16 ++++++++
.../dts/freescale/imx8mm-venice-gw73xx.dtsi | 16 ++++++++
.../dts/freescale/imx8mm-venice-gw7901.dts | 23 +++++++++++
.../dts/freescale/imx8mm-venice-gw7902.dts | 39 ++++++++++++++++++-
.../dts/freescale/imx8mn-venice-gw7902.dts | 39 ++++++++++++++++++-
6 files changed, 145 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
index 506335efc391..73addc0b8e57 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw71xx.dtsi
@@ -68,6 +68,20 @@
status = "okay";
};
+&gpio1 {
+ gpio-line-names = "", "", "", "", "", "", "pci_usb_sel", "dio0",
+ "", "dio1", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio4 {
+ gpio-line-names = "", "", "", "dio2", "dio3", "", "", "pci_wdis#",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
&i2c2 {
clock-frequency = <400000>;
pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi
index 72a3a3aa8fcd..1e7badb2a82e 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi
@@ -88,6 +88,22 @@
status = "okay";
};
+&gpio1 {
+ gpio-line-names = "rs485_term", "mipi_gpio4", "", "",
+ "", "", "pci_usb_sel", "dio0",
+ "", "dio1", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio4 {
+ gpio-line-names = "rs485_en", "mipi_gpio3", "rs485_hd", "mipi_gpio2",
+ "mipi_gpio1", "", "", "pci_wdis#",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
&i2c2 {
clock-frequency = <400000>;
pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi
index 7b00b6b5bb38..426483ec1f88 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi
@@ -108,6 +108,22 @@
status = "okay";
};
+&gpio1 {
+ gpio-line-names = "rs485_term", "mipi_gpio4", "", "",
+ "", "", "pci_usb_sel", "dio0",
+ "", "dio1", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio4 {
+ gpio-line-names = "rs485_en", "mipi_gpio3", "rs485_hd", "mipi_gpio2",
+ "mipi_gpio1", "", "", "pci_wdis#",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
&i2c2 {
clock-frequency = <400000>;
pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
index ca754dff918d..7e7231046215 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7901.dts
@@ -293,6 +293,29 @@
};
};
+&gpio1 {
+ gpio-line-names = "uart1_rs422#", "", "", "uart1_rs485#",
+ "", "uart1_rs232#", "dig1_in", "dig1_out",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio4 {
+ gpio-line-names = "", "", "", "",
+ "", "", "uart3_rs232#", "uart3_rs422#",
+ "uart3_rs485#", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "uart4_rs485#", "", "sim1det#", "sim2det#", "";
+};
+
+&gpio5 {
+ gpio-line-names = "", "", "", "dig2_out", "dig2_in", "sim2sel", "", "",
+ "", "", "uart4_rs232#", "", "", "uart4_rs422#", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
&gpu_2d {
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
index 1b2aaf299b24..edf0c7aaaef0 100644
--- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts
@@ -260,6 +260,43 @@
};
};
+&gpio1 {
+ gpio-line-names = "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "m2_reset", "", "m2_wdis#",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio2 {
+ gpio-line-names = "", "", "", "", "", "", "", "",
+ "uart2_en#", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio3 {
+ gpio-line-names = "", "m2_gdis#", "", "", "", "", "", "m2_off#",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio4 {
+ gpio-line-names = "", "", "", "", "", "", "", "",
+ "", "", "", "amp_gpio3", "amp_gpio2", "", "amp_gpio1", "",
+ "", "", "", "", "amp_gpio4", "app_gpio1", "", "uart1_rs485",
+ "", "uart1_term", "uart1_half", "app_gpio2",
+ "mipi_gpio1", "", "", "";
+};
+
+&gpio5 {
+ gpio-line-names = "", "", "", "mipi_gpio4",
+ "mipi_gpio3", "mipi_gpio2", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
@@ -691,7 +728,7 @@
pinctrl_hog: hoggrp {
fsl,pins = <
MX8MM_IOMUXC_NAND_CE0_B_GPIO3_IO1 0x40000159 /* M2_GDIS# */
- MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x40000041 /* M2_RST# */
+ MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x40000041 /* M2_RESET */
MX8MM_IOMUXC_NAND_DATA01_GPIO3_IO7 0x40000119 /* M2_OFF# */
MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x40000159 /* M2_WDIS# */
MX8MM_IOMUXC_SAI1_TXD2_GPIO4_IO14 0x40000041 /* AMP GPIO1 */
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
index 2d58005d20e4..3c0e63d2e82d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mn-venice-gw7902.dts
@@ -255,6 +255,43 @@
};
};
+&gpio1 {
+ gpio-line-names = "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "m2_reset", "", "m2_wdis#",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio2 {
+ gpio-line-names = "", "", "", "", "", "", "", "",
+ "uart2_en#", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio3 {
+ gpio-line-names = "", "m2_gdis#", "", "", "", "", "", "m2_off#",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
+&gpio4 {
+ gpio-line-names = "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "app_gpio1", "", "uart1_rs485",
+ "", "uart1_term", "uart1_half", "app_gpio2",
+ "mipi_gpio1", "", "", "";
+};
+
+&gpio5 {
+ gpio-line-names = "", "", "", "mipi_gpio4",
+ "mipi_gpio3", "mipi_gpio2", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "";
+};
+
&gpu {
status = "disabled";
};
@@ -645,7 +682,7 @@
pinctrl_hog: hoggrp {
fsl,pins = <
MX8MN_IOMUXC_NAND_CE0_B_GPIO3_IO1 0x40000159 /* M2_GDIS# */
- MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x40000041 /* M2_RST# */
+ MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x40000041 /* M2_RESET */
MX8MN_IOMUXC_NAND_DATA01_GPIO3_IO7 0x40000119 /* M2_OFF# */
MX8MN_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x40000159 /* M2_WDIS# */
MX8MN_IOMUXC_SAI2_RXFS_GPIO4_IO21 0x40000041 /* APP GPIO1 */
--
2.17.1
^ permalink raw reply related
* [PATCH v2 4/4] arm64: dts: rockchip: add Quartz64-A con40 hardware
From: Peter Geis @ 2022-01-28 0:38 UTC (permalink / raw)
To: Rob Herring, Heiko Stuebner
Cc: Peter Geis, devicetree, linux-arm-kernel, linux-rockchip,
linux-kernel
In-Reply-To: <20220128003809.3291407-1-pgwipeout@gmail.com>
The Quartz64-A has a 40 pin connector that exposes various functions.
Annotate the functions exposed in the device tree.
Enable i2c3, which is pulled up to vcc_3v3 on board.
The following functions are currently exposed:
i2c3
spi1
uart2
uart0
spdif
Signed-off-by: Peter Geis <pgwipeout@gmail.com>
---
.../boot/dts/rockchip/rk3566-quartz64-a.dts | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
index c5a79046a9d0..d3dc60ff60dd 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
@@ -449,6 +449,14 @@ regulator-state-mem {
};
};
+/* i2c3 is exposed on con40
+ * pin 3 - i2c3_sda_m0, pullup to vcc_3v3
+ * pin 5 - i2c3_scl_m0, pullup to vcc_3v3
+ */
+&i2c3 {
+ status = "okay";
+};
+
&i2s1_8ch {
pinctrl-names = "default";
pinctrl-0 = <&i2s1m0_sclktx
@@ -559,10 +567,17 @@ &sdmmc1 {
status = "okay";
};
+/* spdif is exposed on con40 pin 18 */
&spdif {
status = "okay";
};
+/* spi1 is exposed on con40
+ * pin 11 - spi1_mosi_m1
+ * pin 13 - spi1_miso_m1
+ * pin 15 - spi1_clk_m1
+ * pin 17 - spi1_cs0_m1
+ */
&spi1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1m1_cs0 &spi1m1_pins>;
@@ -576,6 +591,10 @@ &tsadc {
status = "okay";
};
+/* uart0 is exposed on con40
+ * pin 12 - uart0_tx
+ * pin 14 - uart0_rx
+ */
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_xfer>;
@@ -602,6 +621,10 @@ bluetooth {
};
};
+/* uart2 is exposed on con40
+ * pin 8 - uart2_tx_m0_debug
+ * pin 10 - uart2_rx_m0_debug
+ */
&uart2 {
status = "okay";
};
--
2.25.1
^ permalink raw reply related
* [PATCH v2 3/4] arm64: dts: rockchip: add Quartz64-A sdmmc1 node
From: Peter Geis @ 2022-01-28 0:38 UTC (permalink / raw)
To: Rob Herring, Heiko Stuebner
Cc: Peter Geis, devicetree, linux-arm-kernel, linux-rockchip,
linux-kernel
In-Reply-To: <20220128003809.3291407-1-pgwipeout@gmail.com>
The sdmmc1 node on Quartz64-A supports the optional wifi module from
Pine64.
Add the sdmmc1 node and requisite sdio_pwrseq to enable wifi support on
the Quartz64-A.
Signed-off-by: Peter Geis <pgwipeout@gmail.com>
---
Changelog:
v2:
- drop status = "okay" from sdio_pwrseq
- drop disable-wp from sdmmc1
- move reset-gpios to be alphabetical in sdio_pwrseq
---
.../boot/dts/rockchip/rk3566-quartz64-a.dts | 43 +++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
index 33c2c18caaa9..c5a79046a9d0 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
@@ -91,6 +91,17 @@ simple-audio-card,codec {
};
};
+ sdio_pwrseq: sdio-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&rk817 1>;
+ clock-names = "ext_clock";
+ pinctrl-names = "default";
+ pinctrl-0 = <&wifi_enable_h>;
+ post-power-on-delay-ms = <100>;
+ power-off-delay-us = <5000000>;
+ reset-gpios = <&gpio2 RK_PC2 GPIO_ACTIVE_LOW>;
+ };
+
vcc12v_dcin: vcc12v_dcin {
compatible = "regulator-fixed";
regulator-name = "vcc12v_dcin";
@@ -147,6 +158,17 @@ vcc_sys: vcc_sys {
regulator-max-microvolt = <4400000>;
vin-supply = <&vbus>;
};
+
+ /* sourced from vcc_sys, sdio module operates internally at 3.3v */
+ vcc_wl: vcc_wl {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_wl";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc_sys>;
+ };
};
&cpu0 {
@@ -475,6 +497,12 @@ pmic_int_l: pmic-int-l {
};
};
+ sdio-pwrseq {
+ wifi_enable_h: wifi-enable-h {
+ rockchip,pins = <2 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
vcc_sd {
vcc_sd_h: vcc-sd-h {
rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
@@ -516,6 +544,21 @@ &sdmmc0 {
status = "okay";
};
+&sdmmc1 {
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-sdio-irq;
+ keep-power-in-suspend;
+ mmc-pwrseq = <&sdio_pwrseq>;
+ non-removable;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc1_bus4 &sdmmc1_cmd &sdmmc1_clk>;
+ sd-uhs-sdr104;
+ vmmc-supply = <&vcc_wl>;
+ vqmmc-supply = <&vcc_1v8>;
+ status = "okay";
+};
+
&spdif {
status = "okay";
};
--
2.25.1
^ permalink raw reply related
* [PATCH v2 2/4] arm64: dts: rockchip: add Quartz64-A pmu_io_domains
From: Peter Geis @ 2022-01-28 0:38 UTC (permalink / raw)
To: Rob Herring, Heiko Stuebner
Cc: Peter Geis, devicetree, linux-arm-kernel, linux-rockchip,
linux-kernel
In-Reply-To: <20220128003809.3291407-1-pgwipeout@gmail.com>
Several io power domains on the Quartz64-A operate at 1.8v.
Add the pmu_io_domains definition to enable support for this.
This permits the enablement of the following features:
sdio - wifi support
sdhci - mmc-hs200-1_8v
Signed-off-by: Peter Geis <pgwipeout@gmail.com>
---
arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
index d9eb92d59099..33c2c18caaa9 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
@@ -482,6 +482,19 @@ vcc_sd_h: vcc-sd-h {
};
};
+&pmu_io_domains {
+ pmuio1-supply = <&vcc3v3_pmu>;
+ pmuio2-supply = <&vcc3v3_pmu>;
+ vccio1-supply = <&vccio_acodec>;
+ vccio2-supply = <&vcc_1v8>;
+ vccio3-supply = <&vccio_sd>;
+ vccio4-supply = <&vcc_1v8>;
+ vccio5-supply = <&vcc_3v3>;
+ vccio6-supply = <&vcc1v8_dvp>;
+ vccio7-supply = <&vcc_3v3>;
+ status = "okay";
+};
+
&sdhci {
bus-width = <8>;
mmc-hs200-1_8v;
--
2.25.1
^ permalink raw reply related
* [PATCH v2 1/4] arm64: dts: rockchip: fix Quartz64-A ddr regulator voltage
From: Peter Geis @ 2022-01-28 0:38 UTC (permalink / raw)
To: Rob Herring, Heiko Stuebner, Peter Geis
Cc: Rob Herring, devicetree, linux-arm-kernel, linux-rockchip,
linux-kernel
In-Reply-To: <20220128003809.3291407-1-pgwipeout@gmail.com>
The Quartz64 Model A uses a voltage divider to ensure ddr voltage is
within specification from the default regulator configuration.
Adjusting this voltage is detrimental, and currently causes the ddr
voltage to be about 0.8v.
Remove the min and max voltage setpoints for the ddr regulator.
Fixes: b33a22a1e7c4 ("arm64: dts: rockchip: add basic dts for Pine64
Quartz64-A")
Signed-off-by: Peter Geis <pgwipeout@gmail.com>
---
arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts | 2 --
1 file changed, 2 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
index 166399b7f13f..d9eb92d59099 100644
--- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
@@ -285,8 +285,6 @@ regulator-state-mem {
vcc_ddr: DCDC_REG3 {
regulator-always-on;
regulator-boot-on;
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
regulator-initial-mode = <0x2>;
regulator-name = "vcc_ddr";
regulator-state-mem {
--
2.25.1
^ permalink raw reply related
* [PATCH v2 0/4] Quartz64-A fixes and enablement from 5.17-rc1
From: Peter Geis @ 2022-01-28 0:38 UTC (permalink / raw)
Cc: Peter Geis, Rob Herring, Heiko Stuebner, devicetree,
linux-arm-kernel, linux-rockchip, linux-kernel
Good Evening,
This is the first of several patch series for further expanding
Quartz64-A support.
This series has the following patches:
Fix the ddr regulator voltage.
Add pmu_io_domains to permit sdio and high speed emmc support.
Add sdmmc1 node for wifi support.
Annotate con40 functions and enable i2c3.
Please review and apply.
Very Respectfully,
Peter Geis
Changelog:
v2:
- drop status = "okay" from sdio_pwrseq
- drop disable-wp from sdmmc1
- move reset-gpios to be alphabetical in sdio_pwrseq
- add con40 annotation patch
Peter Geis (4):
arm64: dts: rockchip: fix Quartz64-A ddr regulator voltage
arm64: dts: rockchip: add Quartz64-A pmu_io_domains
arm64: dts: rockchip: add Quartz64-A sdmmc1 node
arm64: dts: rockchip: add Quartz64-A con40 hardware
.../boot/dts/rockchip/rk3566-quartz64-a.dts | 81 ++++++++++++++++++-
1 file changed, 79 insertions(+), 2 deletions(-)
--
2.25.1
^ permalink raw reply
* Re: [PATCH v3 2/3] spi: s3c64xx: Add spi port configuration for Tesla FSD SoC
From: Linus Walleij @ 2022-01-28 0:28 UTC (permalink / raw)
To: Alim Akhtar
Cc: linux-arm-kernel, linux-kernel, devicetree, robh+dt,
krzysztof.kozlowski, linux-samsung-soc, pankaj.dubey, broonie,
andi, linux-spi, linux-fsd, Aswani Reddy
In-Reply-To: <20220125031604.76009-3-alim.akhtar@samsung.com>
On Tue, Jan 25, 2022 at 4:28 AM Alim Akhtar <alim.akhtar@samsung.com> wrote:
> Add compatible and port configuration for spi controller
> for Tesla Full Self-Driving SoC.
>
> Cc: linux-fsd@tesla.com
> Signed-off-by: Aswani Reddy <aswani.reddy@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
> Reviewed-by: Andi Shyti <andi@etezian.org>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Now I however remember that there was some discussion around
the compatible naming. I do not especially care which naming we end
up with but just make sure the compatible naming is the same in
this compatible as in the rest of the platform.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH v3 1/3] spi: dt-bindings: samsung: Add fsd spi compatible
From: Linus Walleij @ 2022-01-28 0:26 UTC (permalink / raw)
To: Alim Akhtar
Cc: linux-arm-kernel, linux-kernel, devicetree, robh+dt,
krzysztof.kozlowski, linux-samsung-soc, pankaj.dubey, broonie,
andi, linux-spi, linux-fsd, Adithya K V
In-Reply-To: <20220125031604.76009-2-alim.akhtar@samsung.com>
On Tue, Jan 25, 2022 at 4:28 AM Alim Akhtar <alim.akhtar@samsung.com> wrote:
> Adds spi controller dt-binding compatible information for
> Tesla Full Self-Driving (FSD) SoC.
>
> Cc: linux-fsd@tesla.com
> Signed-off-by: Adithya K V <adithya.kv@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
> Reviewed-by: Andi Shyti <andi@etezian.org>
The SoC is confirmed to be Tesla-specific, so:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH] dt-bindings: mtd: drop mtd/cortina,gemini-flash.txt
From: Linus Walleij @ 2022-01-28 0:18 UTC (permalink / raw)
To: Corentin Labbe
Cc: miquel.raynal, richard, robh+dt, vigneshr, devicetree,
linux-arm-kernel, linux-kernel, linux-mtd
In-Reply-To: <20220127200310.4150981-1-clabbe@baylibre.com>
On Thu, Jan 27, 2022 at 9:03 PM Corentin Labbe <clabbe@baylibre.com> wrote:
> Drop mtd/cortina,gemini-flash.txt since it is nearly already handled by
> Documentation/devicetree/bindings/mtd/mtd-physmap.yaml.
>
> Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
Thanks for fixing this Corentin!
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description:
> + Phandle to the syscom controller
syscon?
With that small fix:
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Yours,
Linus Walleij
^ permalink raw reply
* RE: [PATCH 1/2] dt-bindings: iommu: renesas,ipmmu-vmsa: add r8a779f0 support
From: Yoshihiro Shimoda @ 2022-01-28 0:09 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Joerg Roedel, Will Deacon, Rob Herring, Linux IOMMU,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Linux-Renesas, Laurent Pinchart, Magnus Damm
In-Reply-To: <CAMuHMdXgg8XApJETkN1oDDSy=N01kJaTz4DADyD9ZOM0ZXXttA@mail.gmail.com>
Hi Geert-san,
Thank you for your review!
> From: Geert Uytterhoeven, Sent: Thursday, January 27, 2022 8:06 PM
>
> Hi Shimoda-san,
>
> CC Laurent, Magnus.
>
> On Tue, Jan 25, 2022 at 6:33 PM Yoshihiro Shimoda
> <yoshihiro.shimoda.uh@renesas.com> wrote:
> > Document the compatible values for the IPMMU-VMSA blocks in
> > the Renesas R-Car S4-8 (R8A779F0) SoC and R-Car Gen4.
> >
> > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
>
> Thanks for your patch!
>
> > --- a/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.yaml
> > +++ b/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.yaml
> > @@ -44,6 +44,10 @@ properties:
> > - renesas,ipmmu-r8a77990 # R-Car E3
> > - renesas,ipmmu-r8a77995 # R-Car D3
> > - renesas,ipmmu-r8a779a0 # R-Car V3U
> > + - items:
> > + - enum:
> > + - renesas,ipmmu-r8a779f0 # R-Car S4-8
> > + - const: renesas,rcar-gen4-ipmmu-vmsa # R-Car Gen4
> >
>
> I'm wondering if we need the family-specific fallback.
> For R-Car Gen3, we don't have it, and match on (all) the SoC-specific
> compatible values instead.
> Do you remember why we decided to do it that way?
>
> At least R-Car V3M/V3H/D3 have slight differences in the register bits,
> but I don't think that was the reason.
I don't remember why... Maybe, we had never discussed this topic?
I searched this topic a little on the ML archive, but I could not find it...
Since upcoming R-Car Gen4 SoC's IPMMU is the same specification with r8a779f0,
I believe renesas,rcar-gen4-ipmmu-vmsa is helpful to support it.
Best regards,
Yoshihiro Shimoda
>
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
> -- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: rockchip: add Quartz64-A sdmmc1 node
From: Peter Geis @ 2022-01-27 23:32 UTC (permalink / raw)
To: Heiko Stübner
Cc: Johan Jonker, Rob Herring, devicetree, arm-mail-list,
open list:ARM/Rockchip SoC..., Linux Kernel Mailing List
In-Reply-To: <3859424.JUeRptVaKW@diego>
On Thu, Jan 27, 2022 at 5:15 AM Heiko Stübner <heiko@sntech.de> wrote:
>
> Am Donnerstag, 27. Januar 2022, 10:55:13 CET schrieb Peter Geis:
> > On Thu, Jan 27, 2022 at 1:18 AM Johan Jonker <jbx6244@gmail.com> wrote:
> > >
> > >
> > >
> > > On 1/27/22 02:00, Peter Geis wrote:
> > > > The sdmmc1 node on Quartz64-A supports the optional wifi module from
> > > > Pine64.
> > > > Add the sdmmc1 node and requisite sdio_pwrseq to enable wifi support on
> > > > the Quartz64-A.
> > > >
> > > > Signed-off-by: Peter Geis <pgwipeout@gmail.com>
> > > > ---
> > > > .../boot/dts/rockchip/rk3566-quartz64-a.dts | 45 +++++++++++++++++++
> > > > 1 file changed, 45 insertions(+)
> > > >
> > > > diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
> > > > index 33c2c18caaa9..1d73ac6557c5 100644
> > > > --- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
> > > > +++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
> > > > @@ -91,6 +91,18 @@ simple-audio-card,codec {
> > > > };
> > > > };
> > > >
> > > > + sdio_pwrseq: sdio-pwrseq {
> > >
> > > > + status = "okay";
> > >
> > > When a node is not previously disabled, then there's no need for "okay".
> >
> > Thanks, this is here in case an end user wants to easily hack the
> > board to use this for other purposes.
>
> but please drop it here as well.
>
> A user "hacking" a devicetree should be able to also just _add_
> a status "disabled" :-) .
Understood, will do.
Thanks!
>
>
^ permalink raw reply
* Re: [PATCH 1/2] arm64: dts: rockchip: rename and sort the rk356x usb2 phy handles
From: Peter Geis @ 2022-01-27 23:32 UTC (permalink / raw)
To: Michael Riesch
Cc: arm-mail-list, open list:ARM/Rockchip SoC..., devicetree,
Linux Kernel Mailing List, Rob Herring, Heiko Stuebner,
Nicolas Frattaroli, Liang Chen
In-Reply-To: <20220127190456.2195527-1-michael.riesch@wolfvision.net>
On Thu, Jan 27, 2022 at 2:05 PM Michael Riesch
<michael.riesch@wolfvision.net> wrote:
>
> All nodes and handles related to USB have the prefix usb or usb2,
> whereas the phy handles are prefixed with u2phy. Rename for
> consistency reasons and to facilitate sorting.
>
> This patch also updates the handles in the only board file that
> uses them (rk3566-quartz64-a.dts).
Good Evening,
While I'm not against this idea, my main concern still stands.
I spent a great deal of thought on this, and decided to go the route I
did to maintain consistency with previous generations.
As such, I see one of three paths here:
- Pull this patch only and depart rk356x from previous SoCs.
- Do the same for previous SoCs to maintain consistency.
- Drop this patch to maintain consistency with previous SoCs.
I ask that others weigh in here, as offline discussion has produced
mixed results already.
Thanks,
Peter
>
> Signed-off-by: Michael Riesch <michael.riesch@wolfvision.net>
> ---
> .../boot/dts/rockchip/rk3566-quartz64-a.dts | 18 ++++++++---------
> arch/arm64/boot/dts/rockchip/rk356x.dtsi | 20 +++++++++----------
> 2 files changed, 19 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
> index f1d6bf10c650..3e65465ac7d5 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
> @@ -574,32 +574,32 @@ &uart2 {
> status = "okay";
> };
>
> -&u2phy1_host {
> - phy-supply = <&vcc5v0_usb20_host>;
> +&usb_host0_ehci {
> status = "okay";
> };
>
> -&u2phy1_otg {
> - phy-supply = <&vcc5v0_usb20_host>;
> +&usb_host0_ohci {
> status = "okay";
> };
>
> -&u2phy1 {
> +&usb_host1_ehci {
> status = "okay";
> };
>
> -&usb_host0_ehci {
> +&usb_host1_ohci {
> status = "okay";
> };
>
> -&usb_host0_ohci {
> +&usb2phy1 {
> status = "okay";
> };
>
> -&usb_host1_ehci {
> +&usb2phy1_host {
> + phy-supply = <&vcc5v0_usb20_host>;
> status = "okay";
> };
>
> -&usb_host1_ohci {
> +&usb2phy1_otg {
> + phy-supply = <&vcc5v0_usb20_host>;
> status = "okay";
> };
> diff --git a/arch/arm64/boot/dts/rockchip/rk356x.dtsi b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
> index 8ee2fab676f4..69c30992ced2 100644
> --- a/arch/arm64/boot/dts/rockchip/rk356x.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk356x.dtsi
> @@ -214,7 +214,7 @@ usb_host0_ehci: usb@fd800000 {
> interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
> clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>,
> <&cru PCLK_USB>;
> - phys = <&u2phy1_otg>;
> + phys = <&usb2phy1_otg>;
> phy-names = "usb";
> status = "disabled";
> };
> @@ -225,7 +225,7 @@ usb_host0_ohci: usb@fd840000 {
> interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> clocks = <&cru HCLK_USB2HOST0>, <&cru HCLK_USB2HOST0_ARB>,
> <&cru PCLK_USB>;
> - phys = <&u2phy1_otg>;
> + phys = <&usb2phy1_otg>;
> phy-names = "usb";
> status = "disabled";
> };
> @@ -236,7 +236,7 @@ usb_host1_ehci: usb@fd880000 {
> interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
> clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>,
> <&cru PCLK_USB>;
> - phys = <&u2phy1_host>;
> + phys = <&usb2phy1_host>;
> phy-names = "usb";
> status = "disabled";
> };
> @@ -247,7 +247,7 @@ usb_host1_ohci: usb@fd8c0000 {
> interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
> clocks = <&cru HCLK_USB2HOST1>, <&cru HCLK_USB2HOST1_ARB>,
> <&cru PCLK_USB>;
> - phys = <&u2phy1_host>;
> + phys = <&usb2phy1_host>;
> phy-names = "usb";
> status = "disabled";
> };
> @@ -1195,7 +1195,7 @@ pwm15: pwm@fe700030 {
> status = "disabled";
> };
>
> - u2phy0: usb2phy@fe8a0000 {
> + usb2phy0: usb2phy@fe8a0000 {
> compatible = "rockchip,rk3568-usb2phy";
> reg = <0x0 0xfe8a0000 0x0 0x10000>;
> clocks = <&pmucru CLK_USBPHY0_REF>;
> @@ -1206,18 +1206,18 @@ u2phy0: usb2phy@fe8a0000 {
> #clock-cells = <0>;
> status = "disabled";
>
> - u2phy0_host: host-port {
> + usb2phy0_host: host-port {
> #phy-cells = <0>;
> status = "disabled";
> };
>
> - u2phy0_otg: otg-port {
> + usb2phy0_otg: otg-port {
> #phy-cells = <0>;
> status = "disabled";
> };
> };
>
> - u2phy1: usb2phy@fe8b0000 {
> + usb2phy1: usb2phy@fe8b0000 {
> compatible = "rockchip,rk3568-usb2phy";
> reg = <0x0 0xfe8b0000 0x0 0x10000>;
> clocks = <&pmucru CLK_USBPHY1_REF>;
> @@ -1228,12 +1228,12 @@ u2phy1: usb2phy@fe8b0000 {
> #clock-cells = <0>;
> status = "disabled";
>
> - u2phy1_host: host-port {
> + usb2phy1_host: host-port {
> #phy-cells = <0>;
> status = "disabled";
> };
>
> - u2phy1_otg: otg-port {
> + usb2phy1_otg: otg-port {
> #phy-cells = <0>;
> status = "disabled";
> };
> --
> 2.30.2
>
^ permalink raw reply
* Re: [PATCH v4 RESEND 3/4] power: supply: Add charger driver for Rockchip RK817
From: Peter Geis @ 2022-01-27 23:27 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Chris Morgan, open list:ARM/Rockchip SoC..., Lee Jones,
Rob Herring, Heiko Stuebner, maccraft123mc, devicetree, linux-pm,
Chris Morgan
In-Reply-To: <20211013174021.z3d7vuupi76rizr4@earth.universe>
On Wed, Oct 13, 2021 at 1:42 PM Sebastian Reichel
<sebastian.reichel@collabora.com> wrote:
>
> Hi,
Good Evening,
I've started looking into the feasibility of supporting rk818 as well with this.
While doing this, I noticed a quirk, which is addressed below.
Do you happen to have experience with the rk818?
Thanks,
Peter
>
> On Thu, Sep 16, 2021 at 02:42:07PM -0500, Chris Morgan wrote:
> > Add support for the Rockchip rk817 battery charger integrated into the
> > rk817 PMIC.
> >
> > Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
> > Signed-off-by: Maya Matuszczyk <maccraft123mc@gmail.com>
> > ---
> > drivers/power/supply/Kconfig | 6 +
> > drivers/power/supply/Makefile | 1 +
> > drivers/power/supply/rk817_charger.c | 959 +++++++++++++++++++++++++++
> > 3 files changed, 966 insertions(+)
> > create mode 100644 drivers/power/supply/rk817_charger.c
>
> Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
>
> -- Sebastian
>
> > diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> > index 11f5368e810e..311130da36ff 100644
> > --- a/drivers/power/supply/Kconfig
> > +++ b/drivers/power/supply/Kconfig
> > @@ -666,6 +666,12 @@ config CHARGER_BQ256XX
> > charge management and system power path management devices for single
> > cell Li-ion and Li-polymer batteries.
> >
> > +config CHARGER_RK817
> > + tristate "Rockchip RK817 PMIC Battery Charger"
> > + depends on MFD_RK808
> > + help
> > + Say Y to include support for Rockchip RK817 Battery Charger.
> > +
> > config CHARGER_SMB347
> > tristate "Summit Microelectronics SMB3XX Battery Charger"
> > depends on I2C
> > diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
> > index 33059a91f60c..9497d2105712 100644
> > --- a/drivers/power/supply/Makefile
> > +++ b/drivers/power/supply/Makefile
> > @@ -87,6 +87,7 @@ obj-$(CONFIG_CHARGER_BQ2515X) += bq2515x_charger.o
> > obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o
> > obj-$(CONFIG_CHARGER_BQ25980) += bq25980_charger.o
> > obj-$(CONFIG_CHARGER_BQ256XX) += bq256xx_charger.o
> > +obj-$(CONFIG_CHARGER_RK817) += rk817_charger.o
> > obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
> > obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
> > obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
> > diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c
> > new file mode 100644
> > index 000000000000..34338aebe269
> > --- /dev/null
> > +++ b/drivers/power/supply/rk817_charger.c
> > @@ -0,0 +1,959 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Charger Driver for Rockchip rk817
> > + *
> > + * Copyright (c) 2021
> > + *
> > + * Authors: Maya Matuszczyk <maccraft123mc@gmail.com>
> > + * Chris Morgan <macromorgan@hotmail.com>
> > + */
> > +
> > +#include <linux/mfd/rk808.h>
> > +#include <linux/irq.h>
> > +#include <linux/of_gpio.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/power_supply.h>
> > +#include <asm/unaligned.h>
> > +
> > +/* Charging statuses reported by hardware register */
> > +enum rk817_charge_status {
> > + CHRG_OFF,
> > + DEAD_CHRG,
> > + TRICKLE_CHRG,
> > + CC_OR_CV_CHRG,
> > + CHARGE_FINISH,
> > + USB_OVER_VOL,
> > + BAT_TMP_ERR,
> > + BAT_TIM_ERR,
> > +};
> > +
> > +/* Max charging current read to/written from hardware register.
> > + * Note how highest value corresponding to 0x7 is the lowest
> > + * current, this is per the datasheet.
> > + */
> > +enum rk817_chg_cur {
> > + CHG_1A,
> > + CHG_1_5A,
> > + CHG_2A,
> > + CHG_2_5A,
> > + CHG_2_75A,
> > + CHG_3A,
> > + CHG_3_5A,
> > + CHG_0_5A,
> > +};
> > +
> > +struct rk817_charger {
> > + struct device *dev;
> > + struct rk808 *rk808;
> > +
> > + struct power_supply *bat_ps;
> > + struct power_supply *chg_ps;
> > + bool plugged_in;
> > +
> > + /* The voltage_k and voltage_b values are used to calibrate the ADC
> > + * voltage readings. While they are documented in the BSP kernel and
> > + * datasheet as voltage_k and voltage_b, there is no further
> > + * information explaining them in more detail.
> > + */
> > +
> > + uint32_t voltage_k;
> > + uint32_t voltage_b;
> > +
> > + /* Storing immutable values of battery here so we can release
> > + * get_battery_info after the probe and use these values.
> > + */
> > + int bat_charge_full_design_uah;
> > + int bat_voltage_min_design_uv;
> > + int bat_voltage_max_design_uv;
> > +
> > + /* dsoc seems to be difference between full charge and actual charge in
> > + * BSP stored as a percentage, to the thousandth.
> > + */
> > + int dsoc;
> > +
> > + /* Calibrate the DSOC on a fully charged battery, this way we can use
> > + * the calibrated DSOC value to correct for columb counter drift.
> > + */
> > + bool dsoc_cal;
> > +
> > + /* Implementation specific properties from device tree */
> > + int res_div;
> > + int sleep_enter_current;
> > + int sleep_filter_current;
> > +};
> > +
> > +/* ADC coefficients extracted from BSP kernel */
> > +#define ADC_TO_CURRENT(adc_value, res_div) \
> > + (adc_value * 172 / res_div)
> > +
> > +#define CURRENT_TO_ADC(current, samp_res) \
> > + (current * samp_res / 172)
> > +
> > +#define CHARGE_TO_ADC(capacity, res_div) \
> > + (capacity * res_div * 3600 / 172 * 1000)
> > +
> > +#define ADC_TO_CHARGE_UAH(adc_value, res_div) \
> > + (adc_value / 3600 * 172 / res_div)
> > +
> > +#define ADC_TO_CAPACITY(adc_value, res_div) \
> > + (adc_value / 1000 * 172 / 3600 / res_div)
> > +
> > +static u8 rk817_chg_cur_to_reg(u32 chg_cur_ma)
> > +{
> > + if (chg_cur_ma > 3500)
> > + return CHG_3_5A;
> > + else if (chg_cur_ma > 3000)
> > + return CHG_3A;
> > + else if (chg_cur_ma > 2750)
> > + return CHG_2_75A;
> > + else if (chg_cur_ma > 2500)
> > + return CHG_2_5A;
> > + else if (chg_cur_ma > 2000)
> > + return CHG_2A;
> > + else if (chg_cur_ma > 1500)
> > + return CHG_1_5A;
> > + else if (chg_cur_ma > 1000)
> > + return CHG_1A;
> > + else if (chg_cur_ma > 500)
> > + return CHG_0_5A;
Shouldn't these be >= ? Otherwise entering the exact value will cause
the next value below to be selected.
> > + else
> > + return -EINVAL;
> > +}
> > +
> > +static int rk817_chg_cur_from_reg(u8 reg)
> > +{
> > + switch (reg) {
> > + case CHG_0_5A:
> > + return 500000;
> > + case CHG_1A:
> > + return 1000000;
> > + case CHG_1_5A:
> > + return 1500000;
> > + case CHG_2A:
> > + return 2000000;
> > + case CHG_2_5A:
> > + return 2500000;
> > + case CHG_2_75A:
> > + return 2750000;
> > + case CHG_3A:
> > + return 3000000;
> > + case CHG_3_5A:
> > + return 3500000;
> > + default:
> > + return -EINVAL;
> > + }
> > +}
> > +
> > +static void rk817_bat_calib_vol(struct rk817_charger *charger)
> > +{
> > + uint32_t vcalib0 = 0;
> > + uint32_t vcalib1 = 0;
> > + u8 bulk_reg[2];
> > +
> > + /* calibrate voltage */
> > + regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_VCALIB0_H,
> > + bulk_reg, 2);
> > + vcalib0 = get_unaligned_be16(bulk_reg);
> > +
> > + regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_VCALIB1_H,
> > + bulk_reg, 2);
> > + vcalib1 = get_unaligned_be16(bulk_reg);
> > +
> > + /* values were taken from BSP kernel */
> > + charger->voltage_k = (4025 - 2300) * 1000 /
> > + ((vcalib1 - vcalib0) ? (vcalib1 - vcalib0) : 1);
> > + charger->voltage_b = 4025 - (charger->voltage_k * vcalib1) / 1000;
> > +}
> > +
> > +static void rk817_bat_calib_cur(struct rk817_charger *charger)
> > +{
> > + u8 bulk_reg[2];
> > +
> > + /* calibrate current */
> > + regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_IOFFSET_H,
> > + bulk_reg, 2);
> > + regmap_bulk_write(charger->rk808->regmap, RK817_GAS_GAUGE_CAL_OFFSET_H,
> > + bulk_reg, 2);
> > +}
> > +
> > +static int rk817_bat_calib_cap(struct rk817_charger *charger)
> > +{
> > + struct rk808 *rk808 = charger->rk808;
> > + int reg, tmp, charge_now, charge_now_adc, dsoc_value;
> > + u8 bulk_reg[4];
> > +
> > + /* Calibrate the dsoc on a fully charged battery */
> > +
> > + regmap_read(rk808->regmap, RK817_PMIC_CHRG_STS, ®);
> > + tmp = (reg >> 4) & 0x07;
> > + if (tmp == CHARGE_FINISH) {
> > + /* Read the columb counter */
> > + regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3,
> > + bulk_reg, 4);
> > + charge_now_adc = get_unaligned_be32(bulk_reg);
> > + if (charge_now_adc < 0)
> > + charge_now_adc = 0;
> > + charge_now = ADC_TO_CHARGE_UAH(charge_now_adc, charger->res_div);
> > +
> > + /* Get and set our DSOC value with a full charge */
> > +
> > + dsoc_value = ((charge_now * 100) /
> > + (charger->bat_charge_full_design_uah / 1000));
> > +
> > + if (!charger->dsoc_cal) {
> > + if (dsoc_value > 100000)
> > + charger->dsoc = 100000;
> > + if (dsoc_value != charger->dsoc) {
> > + charger->dsoc = dsoc_value;
> > + put_unaligned_le24(dsoc_value, bulk_reg);
> > + regmap_bulk_write(rk808->regmap,
> > + RK817_GAS_GAUGE_BAT_R1,
> > + bulk_reg, 3);
> > + }
> > + /* Mark our dsoc as calibrated. */
> > + charger->dsoc_cal = 1;
> > + }
> > +
> > + /* In the event our columb counter has drifted over the
> > + * calibrated dsoc of the battery, adjust the columb counter
> > + * to correct the drift. Don't do this unless we already
> > + * calibrated our dsoc at a fully charged state.
> > + */
> > +
> > + if (dsoc_value > charger->dsoc && charger->dsoc_cal) {
> > + /* Order of operations matters here to ensure we keep
> > + * enough precision until the last step to keep from
> > + * making needless updates to columb counter.
> > + */
> > + charge_now = charger->dsoc *
> > + (charger->bat_charge_full_design_uah
> > + / 1000) / 100;
> > + charge_now_adc = CHARGE_TO_ADC((charge_now / 1000),
> > + charger->res_div);
> > +
> > + put_unaligned_be32(charge_now_adc, bulk_reg);
> > + regmap_bulk_write(rk808->regmap,
> > + RK817_GAS_GAUGE_Q_INIT_H3,
> > + bulk_reg, 4);
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int rk817_bat_get_prop(struct power_supply *ps,
> > + enum power_supply_property prop,
> > + union power_supply_propval *val)
> > +{
> > + struct rk817_charger *charger = power_supply_get_drvdata(ps);
> > + uint32_t tmp = 0;
> > + /* Registers for current is a signed 16bit int */
> > + short int cur = 0;
> > + /* Registers for capacity-now is a signed 32bit int */
> > + int32_t charge_now = 0;
> > + int ret = 0;
> > + int reg = 0;
> > + u8 bulk_reg[4];
> > + struct rk808 *rk808 = charger->rk808;
> > +
> > + /* Recalibrate voltage and current readings if we need to BSP does both
> > + * on CUR_CALIB_UPD, ignoring VOL_CALIB_UPD. Curiously enough, both
> > + * documentation and the BSP show that you perform an update if bit 7
> > + * is 1, but you clear the status by writing a 1 to bit 7.
> > + */
> > + regmap_read(rk808->regmap, RK817_GAS_GAUGE_ADC_CONFIG1, ®);
> > + tmp = (reg >> 7) & 0x01;
> > + if (tmp) {
> > + rk817_bat_calib_cur(charger);
> > + rk817_bat_calib_vol(charger);
> > + regmap_write_bits(rk808->regmap, RK817_GAS_GAUGE_ADC_CONFIG1,
> > + RK817_CUR_CALIB_UPD, (1 << 7));
> > + }
> > +
> > + rk817_bat_calib_cap(charger);
> > +
> > + switch (prop) {
> > + case POWER_SUPPLY_PROP_PRESENT:
> > + regmap_read(rk808->regmap, RK817_PMIC_CHRG_STS, ®);
> > + val->intval = (reg >> 7);
> > + break;
> > + case POWER_SUPPLY_PROP_STATUS:
> > + if (!charger->plugged_in) {
> > + val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
> > + break;
> > + }
> > + ret = regmap_read(rk808->regmap, RK817_PMIC_CHRG_STS, ®);
> > + if (ret)
> > + return ret;
> > + tmp = (reg >> 4) & 0x07;
> > + switch (tmp) {
> > + case CHRG_OFF:
> > + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
> > + break;
> > + /* Dead charge is documented, but not explained. I never
> > + * observed it but assume it's a pre-charge for a dead
> > + * battery.
> > + */
> > + case DEAD_CHRG:
> > + case TRICKLE_CHRG:
> > + case CC_OR_CV_CHRG:
> > + val->intval = POWER_SUPPLY_STATUS_CHARGING;
> > + break;
> > + case CHARGE_FINISH:
> > + val->intval = POWER_SUPPLY_STATUS_FULL;
> > + break;
> > + default:
> > + val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
> > + return -EINVAL;
> > +
> > + }
> > + break;
> > + case POWER_SUPPLY_PROP_CHARGE_TYPE:
> > + ret = regmap_read(rk808->regmap, RK817_PMIC_CHRG_STS, ®);
> > + if (ret)
> > + return ret;
> > + tmp = (reg >> 4) & 0x07;
> > + switch (tmp) {
> > + case CHRG_OFF:
> > + case CHARGE_FINISH:
> > + val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
> > + break;
> > + case TRICKLE_CHRG:
> > + val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
> > + break;
> > + case DEAD_CHRG:
> > + case CC_OR_CV_CHRG:
> > + val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
> > + break;
> > + default:
> > + val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
> > + break;
> > + }
> > + break;
> > + case POWER_SUPPLY_PROP_CHARGE_FULL:
> > + val->intval = ((charger->bat_charge_full_design_uah /
> > + 1000) * charger->dsoc) / 100;
> > + break;
> > + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
> > + val->intval = charger->bat_charge_full_design_uah;
> > + break;
> > + case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
> > + val->intval = 0;
> > + break;
> > + case POWER_SUPPLY_PROP_CHARGE_NOW:
> > + regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3,
> > + bulk_reg, 4);
> > + charge_now = get_unaligned_be32(bulk_reg);
> > + if (charge_now < 0)
> > + charge_now = 0;
> > + val->intval = ADC_TO_CHARGE_UAH(charge_now, charger->res_div);
> > + break;
> > + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
> > + val->intval = charger->bat_voltage_min_design_uv;
> > + break;
> > + case POWER_SUPPLY_PROP_VOLTAGE_BOOT:
> > + regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_PWRON_VOL_H,
> > + bulk_reg, 2);
> > + tmp = get_unaligned_be16(bulk_reg);
> > + val->intval = (charger->voltage_k * tmp) +
> > + 1000 * charger->voltage_b;
> > + break;
> > + case POWER_SUPPLY_PROP_VOLTAGE_AVG:
> > + regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_BAT_VOL_H,
> > + bulk_reg, 2);
> > + tmp = get_unaligned_be16(bulk_reg);
> > + val->intval = (charger->voltage_k * tmp) +
> > + 1000 * charger->voltage_b;
> > + break;
> > + case POWER_SUPPLY_PROP_VOLTAGE_OCV:
> > + regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_OCV_VOL_H,
> > + bulk_reg, 2);
> > + tmp = get_unaligned_be16(bulk_reg);
> > + val->intval = (charger->voltage_k * tmp) +
> > + 1000 * charger->voltage_b;
> > + break;
> > + case POWER_SUPPLY_PROP_CURRENT_BOOT:
> > + regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_PWRON_CUR_H,
> > + bulk_reg, 2);
> > + cur = get_unaligned_be16(bulk_reg);
> > + val->intval = ADC_TO_CURRENT(cur, charger->res_div);
> > + break;
> > + case POWER_SUPPLY_PROP_CURRENT_AVG:
> > + regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_BAT_CUR_H,
> > + bulk_reg, 2);
> > + cur = get_unaligned_be16(bulk_reg);
> > + val->intval = ADC_TO_CURRENT(cur, charger->res_div);
> > + break;
> > + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
> > + regmap_read(rk808->regmap, RK817_PMIC_CHRG_OUT, &tmp);
> > + val->intval = rk817_chg_cur_from_reg(tmp & RK817_CHRG_CUR_SEL);
> > + break;
> > + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
> > + regmap_read(rk808->regmap, RK817_PMIC_CHRG_OUT, &tmp);
> > + val->intval = ((((tmp & RK817_CHRG_VOL_SEL) >> 4) * 50000) +
> > + 4100000);
> > + break;
> > + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
> > + val->intval = charger->bat_voltage_max_design_uv;
> > + break;
> > + default:
> > + return -EINVAL;
> > + }
> > + return 0;
> > +}
> > +
> > +static int rk817_chg_get_prop(struct power_supply *ps,
> > + enum power_supply_property prop,
> > + union power_supply_propval *val)
> > +{
> > + struct rk817_charger *charger = power_supply_get_drvdata(ps);
> > + int vol, tmp = 0;
> > + u8 bulk_reg[2];
> > +
> > + switch (prop) {
> > + case POWER_SUPPLY_PROP_ONLINE:
> > + val->intval = charger->plugged_in;
> > + break;
> > + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
> > + /* max voltage from datasheet at 5.5v (default 5.0v) */
> > + val->intval = 5500000;
> > + break;
> > + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
> > + /* min voltage from datasheet at 3.8v (default 5.0v) */
> > + val->intval = 3800000;
> > + break;
> > + case POWER_SUPPLY_PROP_VOLTAGE_AVG:
> > + /* Note that on my example hardware (an Odroid Go Advance) the
> > + * voltage of the power connector is measured on the register
> > + * labelled USB in the datasheet; I don't know if this is how
> > + * it is designed or just a quirk of the implementation. I
> > + * believe this will also measure the voltage of the USB output
> > + * when in OTG mode, if that is the case we may need to change
> > + * this in the future to return 0 if the power supply status
> > + * is offline.
> > + */
> > + regmap_bulk_read(charger->rk808->regmap,
> > + RK817_GAS_GAUGE_USB_VOL_H,
> > + bulk_reg, 2);
> > + tmp = get_unaligned_be16(bulk_reg);
> > + vol = ((charger->voltage_k * tmp / 1000 + charger->voltage_b) *
> > + 60 / 46);
> > + val->intval = vol * 1000;
> > + break;
> > + /* While it's possible that other implementations could use different
> > + * USB types, the current implementation for this PMIC (the Odroid Go
> > + * Advance) only uses a dedicated charging port with no rx/tx lines.
> > + */
> > + case POWER_SUPPLY_PROP_USB_TYPE:
> > + val->intval = POWER_SUPPLY_USB_TYPE_DCP;
> > + break;
> > + default:
> > + return -EINVAL;
> > + }
> > + return 0;
> > +
> > +}
> > +
> > +static irqreturn_t rk817_plug_in_isr(int irq, void *cg)
> > +{
> > + struct rk817_charger *charger;
> > +
> > + charger = (struct rk817_charger *)cg;
> > + charger->plugged_in = 1;
> > + power_supply_changed(charger->chg_ps);
> > + power_supply_changed(charger->bat_ps);
> > + dev_dbg(charger->dev, "Power Cord Inserted\n");
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static irqreturn_t rk817_plug_out_isr(int irq, void *cg)
> > +{
> > + struct rk817_charger *charger;
> > + struct rk808 *rk808;
> > +
> > + charger = (struct rk817_charger *)cg;
> > + rk808 = charger->rk808;
> > + charger->plugged_in = 0;
> > + power_supply_changed(charger->bat_ps);
> > + power_supply_changed(charger->chg_ps);
> > +
> > + /* For some reason the bits of RK817_PMIC_CHRG_IN reset whenever the
> > + * power cord is unplugged. This was not documented in the BSP kernel
> > + * or the datasheet and only discovered by trial and error. Set minimum
> > + * USB input voltage to 4.5v and enable USB voltage input limit.
> > + */
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
> > + RK817_USB_VLIM_SEL, (0x05 << 4));
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_VLIM_EN,
> > + (0x01 << 7));
> > +
> > + /* Set average USB input current limit to 1.5A and enable USB current
> > + * input limit.
> > + */
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
> > + RK817_USB_ILIM_SEL, 0x03);
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_ILIM_EN,
> > + (0x01 << 3));
> > +
> > + dev_dbg(charger->dev, "Power Cord Removed\n");
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static enum power_supply_property rk817_bat_props[] = {
> > + POWER_SUPPLY_PROP_PRESENT,
> > + POWER_SUPPLY_PROP_STATUS,
> > + POWER_SUPPLY_PROP_CHARGE_TYPE,
> > + POWER_SUPPLY_PROP_CHARGE_FULL,
> > + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
> > + POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
> > + POWER_SUPPLY_PROP_CHARGE_NOW,
> > + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
> > + POWER_SUPPLY_PROP_VOLTAGE_BOOT,
> > + POWER_SUPPLY_PROP_VOLTAGE_AVG,
> > + POWER_SUPPLY_PROP_VOLTAGE_OCV,
> > + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
> > + POWER_SUPPLY_PROP_CURRENT_BOOT,
> > + POWER_SUPPLY_PROP_CURRENT_AVG,
> > + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
> > + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
> > +};
> > +
> > +static enum power_supply_property rk817_chg_props[] = {
> > + POWER_SUPPLY_PROP_ONLINE,
> > + POWER_SUPPLY_PROP_USB_TYPE,
> > + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
> > + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
> > + POWER_SUPPLY_PROP_VOLTAGE_AVG,
> > +};
> > +
> > +static enum power_supply_usb_type rk817_usb_type[] = {
> > + POWER_SUPPLY_USB_TYPE_DCP,
> > + POWER_SUPPLY_USB_TYPE_UNKNOWN,
> > +};
> > +
> > +static const struct power_supply_desc rk817_bat_desc = {
> > + .name = "rk817-battery",
> > + .type = POWER_SUPPLY_TYPE_BATTERY,
> > + .properties = rk817_bat_props,
> > + .num_properties = ARRAY_SIZE(rk817_bat_props),
> > + .get_property = rk817_bat_get_prop,
> > +};
> > +
> > +static const struct power_supply_desc rk817_chg_desc = {
> > + .name = "rk817-charger",
> > + .type = POWER_SUPPLY_TYPE_USB,
> > + .usb_types = rk817_usb_type,
> > + .num_usb_types = ARRAY_SIZE(rk817_usb_type),
> > + .properties = rk817_chg_props,
> > + .num_properties = ARRAY_SIZE(rk817_chg_props),
> > + .get_property = rk817_chg_get_prop,
> > +};
> > +
> > +static int
> > +rk817_read_or_set_full_charge_on_boot(struct rk817_charger *charger,
> > + struct power_supply_battery_info *bat_info)
> > +{
> > + struct rk808 *rk808 = charger->rk808;
> > + u8 bulk_reg[4];
> > + u32 design_charge_mah = (charger->bat_charge_full_design_uah / 1000);
> > + u32 boot_voltage, boot_charge, tmp, full_charge_cap;
> > + int ret, boot_capacity;
> > +
> > + /* Read DSOC value if pre-existing. If not, initialize at 100%.
> > + * Note endianness, also register says it's for resistance,
> > + * however BSP kernel treats this as an nvram field for the DSOC
> > + * as best I can tell. Doing the same for backwards compatibility.
> > + */
> > + ret = regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_BAT_R1, bulk_reg, 3);
> > + if (ret < 0)
> > + return ret;
> > + charger->dsoc = get_unaligned_le24(bulk_reg);
> > + /* If we have an invalid DSOC, write 100 (100000) as default. */
> > + if (charger->dsoc < 1000 || charger->dsoc > 100000) {
> > + charger->dsoc = 100000;
> > + put_unaligned_le24(charger->dsoc, bulk_reg);
> > + regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_BAT_R1,
> > + bulk_reg, 3);
> > + }
> > +
> > + /* Register appears to be nvram that stores capacity in mAH. Note
> > + * endianness, keeping consistent with BSP kernel, however it looks
> > + * like we can use any arbitrary method to store value if we don't care
> > + * about compatibility. Additionally, it doesn't appear that this value
> > + * is used for anything, so realistically getting it and setting it is
> > + * to ensure backward compatibility with BSP and serves no purpose with
> > + * this driver, and I'm not sure if the BSP driver does anything with
> > + * this value either.
> > + */
> > +
> > + ret = regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_DATA3, bulk_reg, 3);
> > + if (ret < 0)
> > + return ret;
> > +
> > + full_charge_cap = get_unaligned_le24(bulk_reg);
> > +
> > + /* Sanity checking for values equal to zero or less than would be
> > + * practical for this device (BSP Kernel assumes 500mAH or less) for
> > + * practicality purposes.
> > + */
> > + if (full_charge_cap < 500) {
> > + put_unaligned_le24(design_charge_mah, bulk_reg);
> > + ret = regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_DATA3, bulk_reg, 3);
> > + if (ret < 0)
> > + return ret;
> > + dev_info(charger->dev,
> > + "Invalid NVRAM Data for max charge, setting to design capacity %u uAH\n",
> > + design_charge_mah*1000);
> > + }
> > +
> > + /* Capture boot voltage and look up boot capacity from OCV tables. */
> > +
> > + regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_PWRON_VOL_H,
> > + bulk_reg, 2);
> > + tmp = get_unaligned_be16(bulk_reg);
> > + boot_voltage = (charger->voltage_k * tmp) + 1000 * charger->voltage_b;
> > + /* Since only implementation has no working thermistor, assume 20C for
> > + * OCV lookup. If lookup fails, report error with OCV table.
> > + */
> > + boot_capacity = power_supply_batinfo_ocv2cap(bat_info, boot_voltage, 20);
> > + if (boot_capacity < 0) {
> > + return dev_err_probe(charger->dev,
> > + boot_capacity,
> > + "Unable to read boot charge from OCV table: %i\n",
> > + boot_capacity);
> > + }
> > +
> > + /* Write boot charge to registers, estimate boot charge based on
> > + * capacity and max charge of battery.
> > + */
> > + boot_charge = (boot_capacity * charger->bat_charge_full_design_uah) / 100;
> > + tmp = CHARGE_TO_ADC((boot_charge / 1000), charger->res_div);
> > + put_unaligned_be32(tmp, bulk_reg);
> > + regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_Q_INIT_H3,
> > + bulk_reg, 4);
> > +
> > + /* Set QMAX value to max design capacity. */
> > + tmp = CHARGE_TO_ADC((charger->bat_charge_full_design_uah / 1000),
> > + charger->res_div);
> > + put_unaligned_be32(tmp, bulk_reg);
> > + ret = regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_Q_MAX_H3,
> > + bulk_reg, 4);
> > + if (ret < 0)
> > + return ret;
> > +
> > + return 0;
> > +}
> > +
> > +static int rk817_battery_init(struct rk817_charger *charger,
> > + struct power_supply_battery_info *bat_info)
> > +{
> > + struct rk808 *rk808 = charger->rk808;
> > + u32 tmp, max_chg_vol_mv, max_chg_cur_ma;
> > + u8 max_chg_vol_reg, chg_term_i_reg, max_chg_cur_reg;
> > + int ret, chg_term_ma;
> > + u8 bulk_reg[2];
> > +
> > + /* Get initial plug state */
> > + regmap_read(rk808->regmap, RK817_SYS_STS, &tmp);
> > + charger->plugged_in = (tmp & RK817_PLUG_IN_STS);
> > +
> > + /* Turn on all ADC functions to measure battery, USB, and sys voltage,
> > + * as well as batt temp. Note only tested implementation so far does
> > + * not use a battery with a thermistor.
> > + */
> > + regmap_write(rk808->regmap, RK817_GAS_GAUGE_ADC_CONFIG0, 0xfc);
> > +
> > + /* Set relax mode voltage sampling interval and ADC offset calibration
> > + * interval to 8 minutes to mirror BSP kernel. Set voltage and current
> > + * modes to average to mirror BSP kernel.
> > + */
> > + regmap_write(rk808->regmap, RK817_GAS_GAUGE_GG_CON, 0x04);
> > +
> > + /* Write relax threshold, derived from sleep enter current. */
> > + tmp = CURRENT_TO_ADC(charger->sleep_enter_current, charger->res_div);
> > + put_unaligned_be16(tmp, bulk_reg);
> > + regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_RELAX_THRE_H,
> > + bulk_reg, 2);
> > +
> > + /* Write sleep sample current, derived from sleep filter current. */
> > + tmp = CURRENT_TO_ADC(charger->sleep_filter_current, charger->res_div);
> > + put_unaligned_be16(tmp, bulk_reg);
> > + regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_SLEEP_CON_SAMP_CUR_H,
> > + bulk_reg, 2);
> > +
> > + /* Restart battery relax voltage */
> > + regmap_write_bits(rk808->regmap, RK817_GAS_GAUGE_GG_STS,
> > + RK817_RELAX_VOL_UPD, (0x0 << 2));
> > +
> > + /* Set OCV Threshold Voltage to 127.5mV. This was hard coded like this
> > + * in the BSP.
> > + */
> > + regmap_write(rk808->regmap, RK817_GAS_GAUGE_OCV_THRE_VOL, 0xff);
> > +
> > + /* Set maximum charging voltage to battery max voltage. Trying to be
> > + * incredibly safe with these value, as setting them wrong could
> > + * overcharge the battery, which would be very bad.
> > + */
> > + max_chg_vol_mv = bat_info->constant_charge_voltage_max_uv / 1000;
> > + max_chg_cur_ma = bat_info->constant_charge_current_max_ua / 1000;
> > +
> > + if (max_chg_vol_mv < 4100) {
> > + return dev_err_probe(charger->dev, -EINVAL,
> > + "invalid max charger voltage, value %u unsupported\n",
> > + max_chg_vol_mv * 1000);
> > + }
> > + if (max_chg_vol_mv > 4450) {
> > + dev_info(charger->dev,
> > + "Setting max charge voltage to 4450000uv\n");
> > + max_chg_vol_mv = 4450;
> > + }
> > +
> > + if (max_chg_cur_ma < 500) {
> > + return dev_err_probe(charger->dev, -EINVAL,
> > + "invalid max charger current, value %u unsupported\n",
> > + max_chg_cur_ma * 1000);
> > + }
> > + if (max_chg_cur_ma > 3500)
> > + dev_info(charger->dev,
> > + "Setting max charge current to 3500000ua\n");
> > +
> > + /* Now that the values are sanity checked, if we subtract 4100 from the
> > + * max voltage and divide by 50, we conviently get the exact value for
> > + * the registers, which are 4.1v, 4.15v, 4.2v, 4.25v, 4.3v, 4.35v,
> > + * 4.4v, and 4.45v; these correspond to values 0x00 through 0x07.
> > + */
> > + max_chg_vol_reg = (max_chg_vol_mv - 4100) / 50;
> > +
> > + max_chg_cur_reg = rk817_chg_cur_to_reg(max_chg_cur_ma);
> > +
> > + if (max_chg_vol_reg < 0 || max_chg_vol_reg > 7) {
> > + return dev_err_probe(charger->dev, -EINVAL,
> > + "invalid max charger voltage, value %u unsupported\n",
> > + max_chg_vol_mv * 1000);
> > + }
> > + if (max_chg_cur_reg < 0 || max_chg_cur_reg > 7) {
> > + return dev_err_probe(charger->dev, -EINVAL,
> > + "invalid max charger current, value %u unsupported\n",
> > + max_chg_cur_ma * 1000);
> > + }
> > +
> > + /* Write the values to the registers, and deliver an emergency warning
> > + * in the event they are not written correctly.
> > + */
> > + ret = regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_OUT,
> > + RK817_CHRG_VOL_SEL, (max_chg_vol_reg << 4));
> > + if (ret) {
> > + dev_emerg(charger->dev,
> > + "Danger, unable to set max charger voltage: %u\n",
> > + ret);
> > + }
> > +
> > + ret = regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_OUT,
> > + RK817_CHRG_CUR_SEL, max_chg_cur_reg);
> > + if (ret) {
> > + dev_emerg(charger->dev,
> > + "Danger, unable to set max charger current: %u\n",
> > + ret);
> > + }
> > +
> > + /* Set charge finishing mode to analog */
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_TERM,
> > + RK817_CHRG_TERM_ANA_DIG, (0x0 << 2));
> > +
> > + /* Set charge finish current, warn if value not in range and keep
> > + * default.
> > + */
> > + chg_term_ma = bat_info->charge_term_current_ua / 1000;
> > + if (chg_term_ma < 150 || chg_term_ma > 400) {
> > + dev_warn(charger->dev,
> > + "Invalid charge termination value %u, keeping default\n",
> > + chg_term_ma * 1000);
> > + chg_term_ma = 200;
> > + }
> > +
> > + /* Values of 150ma, 200ma, 300ma, and 400ma correspond to 00, 01, 10,
> > + * and 11.
> > + */
> > + chg_term_i_reg = (chg_term_ma - 100) / 100;
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_TERM,
> > + RK817_CHRG_TERM_ANA_SEL, chg_term_i_reg);
> > +
> > + ret = rk817_read_or_set_full_charge_on_boot(charger, bat_info);
> > + if (ret < 0)
> > + return ret;
> > +
> > + /* Set minimum USB input voltage to 4.5v and enable USB voltage input
> > + * limit.
> > + */
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
> > + RK817_USB_VLIM_SEL, (0x05 << 4));
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_VLIM_EN,
> > + (0x01 << 7));
> > +
> > + /* Set average USB input current limit to 1.5A and enable USB current
> > + * input limit.
> > + */
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
> > + RK817_USB_ILIM_SEL, 0x03);
> > + regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_ILIM_EN,
> > + (0x01 << 3));
> > +
> > + return 0;
> > +}
> > +
> > +static int rk817_charger_probe(struct platform_device *pdev)
> > +{
> > + struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
> > + struct rk817_charger *charger;
> > + struct device_node *node;
> > + struct power_supply_battery_info bat_info = { };
> > + struct device *dev = &pdev->dev;
> > + struct power_supply_config pscfg = {};
> > + int plugin_irq, plugout_irq;
> > + int of_value;
> > + int ret;
> > +
> > + node = of_get_child_by_name(dev->parent->of_node, "battery");
> > + if (!node)
> > + return -ENODEV;
> > +
> > + charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
> > + if (!charger)
> > + return -ENOMEM;
> > +
> > + charger->rk808 = rk808;
> > +
> > + charger->dev = &pdev->dev;
> > + platform_set_drvdata(pdev, charger);
> > +
> > + rk817_bat_calib_vol(charger);
> > +
> > + pscfg.drv_data = charger;
> > + pscfg.of_node = node;
> > +
> > + /* Get sample resistor value. Note only values of 10000 or 20000
> > + * microohms are allowed. Schematic for my test implementation (an
> > + * Odroid Go Advance) shows a 10 milliohm resistor for reference.
> > + */
> > + ret = of_property_read_u32(node, "rockchip,resistor-sense-micro-ohms",
> > + &of_value);
> > + if (ret < 0) {
> > + return dev_err_probe(dev, ret,
> > + "Error reading sample resistor value\n");
> > + }
> > + /* Store as a 1 or a 2, since all we really use the value for is as a
> > + * divisor in some calculations.
> > + */
> > + charger->res_div = (of_value == 20000) ? 2 : 1;
> > +
> > + /* Get sleep enter current value. Not sure what this value is for
> > + * other than to help calibrate the relax threshold.
> > + */
> > + ret = of_property_read_u32(node,
> > + "rockchip,sleep-enter-current-microamp",
> > + &of_value);
> > + if (ret < 0) {
> > + return dev_err_probe(dev, ret,
> > + "Error reading sleep enter cur value\n");
> > + }
> > + charger->sleep_enter_current = of_value;
> > +
> > + /* Get sleep filter current value */
> > + ret = of_property_read_u32(node,
> > + "rockchip,sleep-filter-current-microamp",
> > + &of_value);
> > + if (ret < 0) {
> > + return dev_err_probe(dev, ret,
> > + "Error reading sleep filter cur value\n");
> > + }
> > +
> > + charger->sleep_filter_current = of_value;
> > +
> > + charger->bat_ps = devm_power_supply_register(&pdev->dev,
> > + &rk817_bat_desc, &pscfg);
> > +
> > + charger->chg_ps = devm_power_supply_register(&pdev->dev,
> > + &rk817_chg_desc, &pscfg);
> > +
> > + if (IS_ERR(charger->chg_ps))
> > + return dev_err_probe(dev, -EINVAL,
> > + "Battery failed to probe\n");
> > +
> > + if (IS_ERR(charger->chg_ps))
> > + return dev_err_probe(dev, -EINVAL,
> > + "Charger failed to probe\n");
> > +
> > + ret = power_supply_get_battery_info(charger->bat_ps,
> > + &bat_info);
> > + if (ret) {
> > + return dev_err_probe(dev, ret,
> > + "Unable to get battery info: %d\n", ret);
> > + }
> > +
> > + if ((!bat_info.charge_full_design_uah) ||
> > + (!bat_info.voltage_min_design_uv) ||
> > + (!bat_info.voltage_max_design_uv) ||
> > + (!bat_info.constant_charge_voltage_max_uv) ||
> > + (!bat_info.constant_charge_current_max_ua) ||
> > + (!bat_info.charge_term_current_ua)) {
> > + return dev_err_probe(dev, -EINVAL,
> > + "Required battery info missing.\n");
> > + }
> > +
> > + charger->bat_charge_full_design_uah = bat_info.charge_full_design_uah;
> > + charger->bat_voltage_min_design_uv = bat_info.voltage_min_design_uv;
> > + charger->bat_voltage_max_design_uv = bat_info.voltage_max_design_uv;
> > +
> > + /* Has to run after power_supply_get_battery_info as it depends on some
> > + * values discovered from that routine.
> > + */
> > + ret = rk817_battery_init(charger, &bat_info);
> > + if (ret)
> > + return ret;
> > +
> > + power_supply_put_battery_info(charger->bat_ps, &bat_info);
> > +
> > + plugin_irq = platform_get_irq(pdev, 0);
> > + if (plugin_irq < 0)
> > + return plugin_irq;
> > +
> > + plugout_irq = platform_get_irq(pdev, 1);
> > + if (plugout_irq < 0)
> > + return plugout_irq;
> > +
> > + ret = devm_request_threaded_irq(charger->dev, plugin_irq, NULL,
> > + rk817_plug_in_isr,
> > + IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> > + "rk817_plug_in", charger);
> > + if (ret) {
> > + return dev_err_probe(&pdev->dev, ret,
> > + "plug_in_irq request failed!\n");
> > + }
> > +
> > + ret = devm_request_threaded_irq(charger->dev, plugout_irq, NULL,
> > + rk817_plug_out_isr,
> > + IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> > + "rk817_plug_out", charger);
> > + if (ret) {
> > + return dev_err_probe(&pdev->dev, ret,
> > + "plug_out_irq request failed!\n");
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +
> > +static struct platform_driver rk817_charger_driver = {
> > + .probe = rk817_charger_probe,
> > + .driver = {
> > + .name = "rk817-charger",
> > + },
> > +};
> > +module_platform_driver(rk817_charger_driver);
> > +
> > +MODULE_DESCRIPTION("Battery power supply driver for RK817 PMIC");
> > +MODULE_AUTHOR("Maya Matuszczyk <maccraft123mc@gmail.com>");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.25.1
> >
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
^ permalink raw reply
* Re: [PATCH v2 02/15] dt-bindings: devfreq: rk3399_dmc: Deprecate unused/redundant properties
From: Brian Norris @ 2022-01-27 23:17 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring
Cc: Linux Kernel, open list:ARM/Rockchip SoC..., Lin Huang,
linux-arm-kernel, Derek Basehore, devicetree, linux-pm,
Heiko Stuebner
In-Reply-To: <20220127150615.v2.2.I5ba582cd678d34c03d647e5500db8e33b7524d66@changeid>
On Thu, Jan 27, 2022 at 3:08 PM Brian Norris <briannorris@chromium.org> wrote:
>
> These DRAM configuration properties are all handled in ARM Trusted
> Firmware (and have been since the early days of this SoC), and there are
> no in-tree users of the DMC binding yet. It's better to just defer to
> firmware instead of maintaining this large list of properties.
>
> There's also some confusion about units: many of these are specified in
> MHz, but the downstream users and driver code are treating them as Hz, I
> believe. Rather than straighten all that out, I just drop them.
>
> Signed-off-by: Brian Norris <briannorris@chromium.org>
> ---
>
> (no changes since v1)
Apologies, I didn't include Rob's Reviewed-by tag on patch 2 and 3. If
this goes for version 3, I'll include them.
Brian
^ permalink raw reply
* [PATCH] usb: dwc3: xilinx: fix uninitialized return value
From: Robert Hancock @ 2022-01-27 22:15 UTC (permalink / raw)
To: linux-usb
Cc: balbi, gregkh, michal.simek, manish.narani, sean.anderson,
robh+dt, devicetree, piyush.mehta, Robert Hancock, stable
A previous patch to skip part of the initialization when a USB3 PHY was
not present could result in the return value being uninitialized in that
case, causing spurious probe failures. Initialize ret to 0 to avoid this.
Fixes: 9678f3361afc ("usb: dwc3: xilinx: Skip resets and USB3 register settings for USB2.0 mode")
Cc: <stable@vger.kernel.org>
Signed-off-by: Robert Hancock <robert.hancock@calian.com>
---
drivers/usb/dwc3/dwc3-xilinx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index e14ac15e24c3..a6f3a9b38789 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -99,7 +99,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
struct device *dev = priv_data->dev;
struct reset_control *crst, *hibrst, *apbrst;
struct phy *usb3_phy;
- int ret;
+ int ret = 0;
u32 reg;
usb3_phy = devm_phy_optional_get(dev, "usb3-phy");
--
2.31.1
^ permalink raw reply related
* Re: [PATCH v16 2/4] dmaengine: tegra: Add tegra gpcdma driver
From: Dmitry Osipenko @ 2022-01-27 23:15 UTC (permalink / raw)
To: Akhil R, dan.j.williams@intel.com, devicetree@vger.kernel.org,
dmaengine@vger.kernel.org, Jonathan Hunter, Krishna Yarlagadda,
Laxman Dewangan, linux-kernel@vger.kernel.org,
linux-tegra@vger.kernel.org, p.zabel@pengutronix.de,
Rajesh Gumasta, robh+dt@kernel.org, thierry.reding@gmail.com,
vkoul@kernel.org
Cc: Pavan Kunapuli
In-Reply-To: <DM5PR12MB1850677D5F07065BDC08EE24C0219@DM5PR12MB1850.namprd12.prod.outlook.com>
27.01.2022 19:29, Akhil R пишет:
>> 23.01.2022 19:49, Akhil R пишет:
>>>> 21.01.2022 19:24, Akhil R пишет:
>>>>>>>>>>> +static int tegra_dma_terminate_all(struct dma_chan *dc) {
>>>>>>>>>>> + struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
>>>>>>>>>>> + unsigned long flags;
>>>>>>>>>>> + LIST_HEAD(head);
>>>>>>>>>>> + int err;
>>>>>>>>>>> +
>>>>>>>>>>> + if (tdc->dma_desc) {
>>>>>>>>>>
>>>>>>>>>> Needs locking protection against racing with the interrupt handler.
>>>>>>>>> tegra_dma_stop_client() waits for the in-flight transfer to
>>>>>>>>> complete and prevents any additional transfer to start.
>>>>>>>>> Wouldn't it manage the race? Do you see any potential issue there?
>>>>>>>>
>>>>>>>> You should consider interrupt handler like a process running in a
>>>>>>>> parallel thread. The interrupt handler sets tdc->dma_desc to NULL,
>>>>>>>> hence you'll get NULL dereference in tegra_dma_stop_client().
>>>>>>>
>>>>>>> Is it better if I remove the below part from tegra_dma_stop_client()
>>>>>>> so that dma_desc is not accessed at all?
>>>>>>>
>>>>>>> + wcount = tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT);
>>>>>>> + tdc->dma_desc->bytes_transferred +=
>>>>>>> + tdc->dma_desc->bytes_requested - (wcount * 4);
>>>>>>>
>>>>>>> Because I don't see a point in updating the value there. dma_desc is
>>>>>>> set to NULL in the next step in terminate_all() anyway.
>>>>>>
>>>>>> That isn't going help you much because you also can't release DMA
>>>>>> descriptor while interrupt handler still may be running and using
>>>>>> that descriptor.
>>>>>
>>>>> Does the below functions look good to resolve the issue, provided
>>>>> tegra_dma_stop_client() doesn't access dma_desc?
>>>>
>>>> Stop shall not race with the start.
>>>>
>>>>> +static int tegra_dma_terminate_all(struct dma_chan *dc) {
>>>>> + struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
>>>>> + unsigned long flags;
>>>>> + LIST_HEAD(head);
>>>>> + int err;
>>>>> +
>>>>> + err = tegra_dma_stop_client(tdc);
>>>>> + if (err)
>>>>> + return err;
>>>>> +
>>>>> + tegra_dma_stop(tdc);
>>>>> +
>>>>> + spin_lock_irqsave(&tdc->vc.lock, flags);
>>>>> + tegra_dma_sid_free(tdc);
>>>>> + tdc->dma_desc = NULL;
>>>>> +
>>>>> + vchan_get_all_descriptors(&tdc->vc, &head);
>>>>> + spin_unlock_irqrestore(&tdc->vc.lock, flags);
>>>>> +
>>>>> + vchan_dma_desc_free_list(&tdc->vc, &head);
>>>>> +
>>>>> + return 0;
>>>>> +}
>>>>>
>>>>> +static irqreturn_t tegra_dma_isr(int irq, void *dev_id) {
>>>>> + struct tegra_dma_channel *tdc = dev_id;
>>>>> + struct tegra_dma_desc *dma_desc = tdc->dma_desc;
>>>>> + struct tegra_dma_sg_req *sg_req;
>>>>> + u32 status;
>>>>> +
>>>>> + /* Check channel error status register */
>>>>> + status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS);
>>>>> + if (status) {
>>>>> + tegra_dma_chan_decode_error(tdc, status);
>>>>> + tegra_dma_dump_chan_regs(tdc);
>>>>> + tdc_write(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS, 0xFFFFFFFF);
>>>>> + }
>>>>> +
>>>>> + status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
>>>>> + if (!(status & TEGRA_GPCDMA_STATUS_ISE_EOC))
>>>>> + return IRQ_HANDLED;
>>>>> +
>>>>> + tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS,
>>>>> + TEGRA_GPCDMA_STATUS_ISE_EOC);
>>>>> +
>>>>> + spin_lock(&tdc->vc.lock);
>>>>> + if (!dma_desc)
>>>> All checks and assignments must be done inside of critical section.
>>>
>>> Okay. So, the lock should be held throughout the function.
>>> Do you think tegra_dma_pause should also hold a lock
>>> and remove irq_synchronize? That function also writes
>>> to CSR register.
>>
>> Interrupt handler shall not unpause channel in a case of race condition,
>> it should handle completed transfer and check whether channel is paused
>> before issuing next transfer.
>> So yes, pause also needs a lock.
> Thanks for the points. I collected more details on this scenario and found that
> DMA can only be paused if there is an in-flight transfer (i.e no interrupt will be
> pending). And there cannot be an interrupt after DMA is paused. Hence, there
> is no case of ISR unpausing a paused transfer. So, I guess, the check or a lock
> might not be required there.
If there is in-flight transfer, then interrupt may fire at any time. All
CSRE modifications must be protected.
> One thing I am thinking of is to wait for DMA to be busy so that it can be paused.
> I would add these changes and send out a new patch.
You should assume that interrupt handler may run with a delay. Then
pause() will see that channel isn't busy, but delayed interrupt will
start the next transfer.
Also, the tegra_dma_pause() will crash if tdc->dma_desc=NULL.
Everything must be done under lock.
^ permalink raw reply
* [PATCH v2 15/15] PM / devfreq: rk3399_dmc: Avoid static (reused) profile
From: Brian Norris @ 2022-01-27 23:07 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring
Cc: linux-kernel, linux-rockchip, Lin Huang, linux-arm-kernel,
Derek Basehore, devicetree, linux-pm, Heiko Stuebner,
Brian Norris
In-Reply-To: <20220127230727.3369358-1-briannorris@chromium.org>
This static struct can get reused if the device gets removed/reprobed,
and that causes use-after-free in its ->freq_table.
Let's just move the struct to our dynamic allocation.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Changes in v2:
- New patch
drivers/devfreq/rk3399_dmc.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c
index 9615658d04ae..e494d1497d60 100644
--- a/drivers/devfreq/rk3399_dmc.c
+++ b/drivers/devfreq/rk3399_dmc.c
@@ -38,6 +38,7 @@
struct rk3399_dmcfreq {
struct device *dev;
struct devfreq *devfreq;
+ struct devfreq_dev_profile profile;
struct devfreq_simple_ondemand_data ondemand_data;
struct clk *dmc_clk;
struct devfreq_event_dev *edev;
@@ -228,13 +229,6 @@ static int rk3399_dmcfreq_get_cur_freq(struct device *dev, unsigned long *freq)
return 0;
}
-static struct devfreq_dev_profile rk3399_devfreq_dmc_profile = {
- .polling_ms = 200,
- .target = rk3399_dmcfreq_target,
- .get_dev_status = rk3399_dmcfreq_get_dev_status,
- .get_cur_freq = rk3399_dmcfreq_get_cur_freq,
-};
-
static __maybe_unused int rk3399_dmcfreq_suspend(struct device *dev)
{
struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(dev);
@@ -422,10 +416,16 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
data->volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
- rk3399_devfreq_dmc_profile.initial_freq = data->rate;
+ data->profile = (struct devfreq_dev_profile) {
+ .polling_ms = 200,
+ .target = rk3399_dmcfreq_target,
+ .get_dev_status = rk3399_dmcfreq_get_dev_status,
+ .get_cur_freq = rk3399_dmcfreq_get_cur_freq,
+ .initial_freq = data->rate,
+ };
data->devfreq = devm_devfreq_add_device(dev,
- &rk3399_devfreq_dmc_profile,
+ &data->profile,
DEVFREQ_GOV_SIMPLE_ONDEMAND,
&data->ondemand_data);
if (IS_ERR(data->devfreq)) {
--
2.35.0.rc0.227.g00780c9af4-goog
^ permalink raw reply related
* [PATCH v2 14/15] PM / devfreq: rk3399_dmc: Use devm_pm_opp_of_add_table()
From: Brian Norris @ 2022-01-27 23:07 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring
Cc: linux-kernel, linux-rockchip, Lin Huang, linux-arm-kernel,
Derek Basehore, devicetree, linux-pm, Heiko Stuebner,
Brian Norris
In-Reply-To: <20220127230727.3369358-1-briannorris@chromium.org>
This simplifies error-cleanup and remove().
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Changes in v2:
- New patch
drivers/devfreq/rk3399_dmc.c | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c
index fca9fcbd4249..9615658d04ae 100644
--- a/drivers/devfreq/rk3399_dmc.c
+++ b/drivers/devfreq/rk3399_dmc.c
@@ -401,7 +401,7 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
* We add a devfreq driver to our parent since it has a device tree node
* with operating points.
*/
- if (dev_pm_opp_of_add_table(dev)) {
+ if (devm_pm_opp_of_add_table(dev)) {
dev_err(dev, "Invalid operating-points in device tree.\n");
ret = -EINVAL;
goto err_edev;
@@ -415,7 +415,7 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
opp = devfreq_recommended_opp(dev, &data->rate, 0);
if (IS_ERR(opp)) {
ret = PTR_ERR(opp);
- goto err_free_opp;
+ goto err_edev;
}
data->rate = dev_pm_opp_get_freq(opp);
@@ -430,7 +430,7 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
&data->ondemand_data);
if (IS_ERR(data->devfreq)) {
ret = PTR_ERR(data->devfreq);
- goto err_free_opp;
+ goto err_edev;
}
devm_devfreq_register_opp_notifier(dev, data->devfreq);
@@ -440,8 +440,6 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
return 0;
-err_free_opp:
- dev_pm_opp_of_remove_table(&pdev->dev);
err_edev:
devfreq_event_disable_edev(data->edev);
@@ -454,12 +452,6 @@ static int rk3399_dmcfreq_remove(struct platform_device *pdev)
devfreq_event_disable_edev(dmcfreq->edev);
- /*
- * Before remove the opp table we need to unregister the opp notifier.
- */
- devm_devfreq_unregister_opp_notifier(dmcfreq->dev, dmcfreq->devfreq);
- dev_pm_opp_of_remove_table(dmcfreq->dev);
-
return 0;
}
--
2.35.0.rc0.227.g00780c9af4-goog
^ permalink raw reply related
* [PATCH v2 13/15] PM / devfreq: rk3399_dmc: Disable edev on remove()
From: Brian Norris @ 2022-01-27 23:07 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring
Cc: linux-kernel, linux-rockchip, Lin Huang, linux-arm-kernel,
Derek Basehore, devicetree, linux-pm, Heiko Stuebner,
Brian Norris
In-Reply-To: <20220127230727.3369358-1-briannorris@chromium.org>
Otherwise we hit an unablanced enable-count when unbinding the DFI
device:
[ 1279.659119] ------------[ cut here ]------------
[ 1279.659179] WARNING: CPU: 2 PID: 5638 at drivers/devfreq/devfreq-event.c:360 devfreq_event_remove_edev+0x84/0x8c
...
[ 1279.659352] Hardware name: Google Kevin (DT)
[ 1279.659363] pstate: 80400005 (Nzcv daif +PAN -UAO -TCO BTYPE=--)
[ 1279.659371] pc : devfreq_event_remove_edev+0x84/0x8c
[ 1279.659380] lr : devm_devfreq_event_release+0x1c/0x28
...
[ 1279.659571] Call trace:
[ 1279.659582] devfreq_event_remove_edev+0x84/0x8c
[ 1279.659590] devm_devfreq_event_release+0x1c/0x28
[ 1279.659602] release_nodes+0x1cc/0x244
[ 1279.659611] devres_release_all+0x44/0x60
[ 1279.659621] device_release_driver_internal+0x11c/0x1ac
[ 1279.659629] device_driver_detach+0x20/0x2c
[ 1279.659641] unbind_store+0x7c/0xb0
[ 1279.659650] drv_attr_store+0x2c/0x40
[ 1279.659663] sysfs_kf_write+0x44/0x58
[ 1279.659672] kernfs_fop_write_iter+0xf4/0x190
[ 1279.659684] vfs_write+0x2b0/0x2e4
[ 1279.659693] ksys_write+0x80/0xec
[ 1279.659701] __arm64_sys_write+0x24/0x30
[ 1279.659714] el0_svc_common+0xf0/0x1d8
[ 1279.659724] do_el0_svc_compat+0x28/0x3c
[ 1279.659738] el0_svc_compat+0x10/0x1c
[ 1279.659746] el0_sync_compat_handler+0xa8/0xcc
[ 1279.659758] el0_sync_compat+0x188/0x1c0
[ 1279.659768] ---[ end trace cec200e5094155b4 ]---
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Changes in v2:
- New patch
drivers/devfreq/rk3399_dmc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c
index f778564cab49..fca9fcbd4249 100644
--- a/drivers/devfreq/rk3399_dmc.c
+++ b/drivers/devfreq/rk3399_dmc.c
@@ -452,6 +452,8 @@ static int rk3399_dmcfreq_remove(struct platform_device *pdev)
{
struct rk3399_dmcfreq *dmcfreq = dev_get_drvdata(&pdev->dev);
+ devfreq_event_disable_edev(dmcfreq->edev);
+
/*
* Before remove the opp table we need to unregister the opp notifier.
*/
--
2.35.0.rc0.227.g00780c9af4-goog
^ permalink raw reply related
* [PATCH v2 11/15] arm64: dts: rk3399: Add dfi and dmc nodes
From: Brian Norris @ 2022-01-27 23:07 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring
Cc: linux-kernel, linux-rockchip, Lin Huang, linux-arm-kernel,
Derek Basehore, devicetree, linux-pm, Heiko Stuebner,
Enric Balletbo i Serra, Gaël PORTAY, Daniel Lezcano,
Brian Norris
In-Reply-To: <20220127230727.3369358-1-briannorris@chromium.org>
From: Lin Huang <hl@rock-chips.com>
These are required to support DDR DVFS on RK3399 platforms.
Signed-off-by: Lin Huang <hl@rock-chips.com>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Signed-off-by: Gaël PORTAY <gael.portay@collabora.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Signed-off-by: Brian Norris <briannorris@chromium.org>
Change since Daniel's posting: reordered by unit address, per existing
style
---
Changes in v2:
- rename dmc to memory-controller
Changes in v1:
This is based on a v5 posting from various authors:
https://lore.kernel.org/lkml/20210308233858.24741-3-daniel.lezcano@linaro.org/
Much of that series was already merged, so I start over with the
numbering.
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d3cdf6f42a30..4096ef6f7b72 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1295,6 +1295,25 @@ pwm3: pwm@ff420030 {
status = "disabled";
};
+ dfi: dfi@ff630000 {
+ reg = <0x00 0xff630000 0x00 0x4000>;
+ compatible = "rockchip,rk3399-dfi";
+ rockchip,pmu = <&pmugrf>;
+ interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&cru PCLK_DDR_MON>;
+ clock-names = "pclk_ddr_mon";
+ status = "disabled";
+ };
+
+ dmc: memory-controller {
+ compatible = "rockchip,rk3399-dmc";
+ rockchip,pmu = <&pmugrf>;
+ devfreq-events = <&dfi>;
+ clocks = <&cru SCLK_DDRC>;
+ clock-names = "dmc_clk";
+ status = "disabled";
+ };
+
vpu: video-codec@ff650000 {
compatible = "rockchip,rk3399-vpu";
reg = <0x0 0xff650000 0x0 0x800>;
--
2.35.0.rc0.227.g00780c9af4-goog
^ permalink raw reply related
* [PATCH v2 12/15] arm64: dts: rockchip: Enable dmc and dfi nodes on gru
From: Brian Norris @ 2022-01-27 23:07 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring
Cc: linux-kernel, linux-rockchip, Lin Huang, linux-arm-kernel,
Derek Basehore, devicetree, linux-pm, Heiko Stuebner,
Enric Balletbo i Serra, Gaël PORTAY, Daniel Lezcano,
Brian Norris
In-Reply-To: <20220127230727.3369358-1-briannorris@chromium.org>
From: Lin Huang <hl@rock-chips.com>
Enable the DMC (Dynamic Memory Controller) and the DFI (DDR PHY
Interface) nodes on gru boards so we can support DDR DVFS.
Signed-off-by: Lin Huang <hl@rock-chips.com>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Signed-off-by: Gaël PORTAY <gael.portay@collabora.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Signed-off-by: Brian Norris <briannorris@chromium.org>
Updates since the old series:
- reordered alphabetically by phandle name, per style
- drop a ton of deprecated/unused properties
- add required center-supply for scarlet
- add new *_idle_dis_freq properties
- drop the lowest (200 MHz) OPP; this was never stabilized for
production
- bump the voltage (0.9V -> 0.925V) for the highest OPP on Chromebook
models; later (tablet) models were more stable, with a fixed DDR
regulator
- bump odt_dis_freq to 666 MHz; early versions used 333 MHz, but
stabilization efforts landed on 666 MHz for production
---
Changes in v2:
- Adapt to new properties
Changes in v1:
This was part of a previous series, at:
https://lore.kernel.org/r/20210308233858.24741-3-daniel.lezcano@linaro.org
I've picked up a bunch of changes and fixes, so I've restarted the patch
series numbering.
.../dts/rockchip/rk3399-gru-chromebook.dtsi | 7 +++++
.../boot/dts/rockchip/rk3399-gru-scarlet.dtsi | 12 ++++++++
arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi | 28 +++++++++++++++++++
.../boot/dts/rockchip/rk3399-op1-opp.dtsi | 25 +++++++++++++++++
4 files changed, 72 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
index 9b2c679f5eca..cc8950046d94 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-chromebook.dtsi
@@ -234,6 +234,13 @@ &cdn_dp {
extcon = <&usbc_extcon0>, <&usbc_extcon1>;
};
+&dmc {
+ center-supply = <&ppvar_centerlogic>;
+ rockchip,pd-idle-dis-freq-hz = <800000000>;
+ rockchip,sr-idle-dis-freq-hz = <800000000>;
+ rockchip,sr-mc-gate-idle-dis-freq-hz = <800000000>;
+};
+
&edp {
status = "okay";
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
index a9817b3d7edc..913d845eb51a 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
@@ -391,6 +391,18 @@ &cru {
<400000000>;
};
+/* The center supply is fixed to .9V on scarlet */
+&dmc {
+ center-supply = <&pp900_s0>;
+};
+
+/* We don't need .925 V for 928 MHz on scarlet */
+&dmc_opp_table {
+ opp03 {
+ opp-microvolt = <900000>;
+ };
+};
+
&gpio0 {
gpio-line-names = /* GPIO0 A 0-7 */
"CLK_32K_AP",
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
index 162f08bca0d4..23bfba86daab 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
@@ -373,6 +373,34 @@ &cru {
<200000000>;
};
+&dfi {
+ status = "okay";
+};
+
+&dmc {
+ status = "okay";
+
+ rockchip,pd-idle-ns = <160>;
+ rockchip,sr-idle-ns = <10240>;
+ rockchip,sr-mc-gate-idle-ns = <40960>;
+ rockchip,srpd-lite-idle-ns = <61440>;
+ rockchip,standby-idle-ns = <81920>;
+
+ rockchip,ddr3_odt_dis_freq = <666000000>;
+ rockchip,lpddr3_odt_dis_freq = <666000000>;
+ rockchip,lpddr4_odt_dis_freq = <666000000>;
+
+ rockchip,sr-mc-gate-idle-dis-freq-hz = <1000000000>;
+ rockchip,srpd-lite-idle-dis-freq-hz = <0>;
+ rockchip,standby-idle-dis-freq-hz = <928000000>;
+};
+
+&dmc_opp_table {
+ opp03 {
+ opp-suspend;
+ };
+};
+
&emmc_phy {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-op1-opp.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-op1-opp.dtsi
index 2180e0f75003..6e29e74f6fc6 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-op1-opp.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399-op1-opp.dtsi
@@ -110,6 +110,27 @@ opp05 {
opp-microvolt = <1075000>;
};
};
+
+ dmc_opp_table: dmc_opp_table {
+ compatible = "operating-points-v2";
+
+ opp00 {
+ opp-hz = /bits/ 64 <400000000>;
+ opp-microvolt = <900000>;
+ };
+ opp01 {
+ opp-hz = /bits/ 64 <666000000>;
+ opp-microvolt = <900000>;
+ };
+ opp02 {
+ opp-hz = /bits/ 64 <800000000>;
+ opp-microvolt = <900000>;
+ };
+ opp03 {
+ opp-hz = /bits/ 64 <928000000>;
+ opp-microvolt = <925000>;
+ };
+ };
};
&cpu_l0 {
@@ -136,6 +157,10 @@ &cpu_b1 {
operating-points-v2 = <&cluster1_opp>;
};
+&dmc {
+ operating-points-v2 = <&dmc_opp_table>;
+};
+
&gpu {
operating-points-v2 = <&gpu_opp_table>;
};
--
2.35.0.rc0.227.g00780c9af4-goog
^ permalink raw reply related
* [PATCH v2 10/15] PM / devfreq: rk3399_dmc: Support new *-ns properties
From: Brian Norris @ 2022-01-27 23:07 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring
Cc: linux-kernel, linux-rockchip, Lin Huang, linux-arm-kernel,
Derek Basehore, devicetree, linux-pm, Heiko Stuebner,
Brian Norris
In-Reply-To: <20220127230727.3369358-1-briannorris@chromium.org>
We want to keep the idle time fixed, so compute based on the current DDR
frequency.
The old properties were deprecated and never used, so we can safely drop
them from the driver.
This is a rewritten version of work by Lin Huang <hl@rock-chips.com>.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
Changes in v2:
- New patch
drivers/devfreq/rk3399_dmc.c | 85 +++++++++++++++++++++---------------
1 file changed, 50 insertions(+), 35 deletions(-)
diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c
index fc740c1f6747..f778564cab49 100644
--- a/drivers/devfreq/rk3399_dmc.c
+++ b/drivers/devfreq/rk3399_dmc.c
@@ -24,6 +24,8 @@
#include <soc/rockchip/rk3399_grf.h>
#include <soc/rockchip/rockchip_sip.h>
+#define NS_TO_CYCLE(NS, MHz) (((NS) * (MHz)) / NSEC_PER_USEC)
+
#define RK3399_SET_ODT_PD_0_SR_IDLE GENMASK(7, 0)
#define RK3399_SET_ODT_PD_0_SR_MC_GATE_IDLE GENMASK(15, 8)
#define RK3399_SET_ODT_PD_0_STANDBY_IDLE GENMASK(31, 16)
@@ -45,13 +47,12 @@ struct rk3399_dmcfreq {
unsigned long rate, target_rate;
unsigned long volt, target_volt;
unsigned int odt_dis_freq;
- int odt_pd_arg0, odt_pd_arg1;
- unsigned int pd_idle;
- unsigned int sr_idle;
- unsigned int sr_mc_gate_idle;
- unsigned int srpd_lite_idle;
- unsigned int standby_idle;
+ unsigned int pd_idle_ns;
+ unsigned int sr_idle_ns;
+ unsigned int sr_mc_gate_idle_ns;
+ unsigned int srpd_lite_idle_ns;
+ unsigned int standby_idle_ns;
unsigned int ddr3_odt_dis_freq;
unsigned int lpddr3_odt_dis_freq;
unsigned int lpddr4_odt_dis_freq;
@@ -70,9 +71,14 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
struct dev_pm_opp *opp;
unsigned long old_clk_rate = dmcfreq->rate;
unsigned long target_volt, target_rate;
+ unsigned int ddrcon_mhz;
struct arm_smccc_res res;
int err;
+ u32 odt_pd_arg0 = 0;
+ u32 odt_pd_arg1 = 0;
+ u32 odt_pd_arg2 = 0;
+
opp = devfreq_recommended_opp(dev, freq, flags);
if (IS_ERR(opp))
return PTR_ERR(opp);
@@ -86,11 +92,35 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
mutex_lock(&dmcfreq->lock);
- if (dmcfreq->regmap_pmu) {
- unsigned int odt_pd_arg0 = dmcfreq->odt_pd_arg0;
- unsigned int odt_pd_arg1 = dmcfreq->odt_pd_arg1;
- unsigned int odt_pd_arg2 = 0;
+ /*
+ * Some idle parameters may be based on the DDR controller clock, which
+ * is half of the DDR frequency.
+ * pd_idle and standby_idle are based on the controller clock cycle.
+ * sr_idle_cycle, sr_mc_gate_idle_cycle, and srpd_lite_idle_cycle
+ * are based on the 1024 controller clock cycle
+ */
+ ddrcon_mhz = target_rate / USEC_PER_SEC / 2;
+
+ u32p_replace_bits(&odt_pd_arg1,
+ NS_TO_CYCLE(dmcfreq->pd_idle_ns, ddrcon_mhz),
+ RK3399_SET_ODT_PD_1_PD_IDLE);
+ u32p_replace_bits(&odt_pd_arg0,
+ NS_TO_CYCLE(dmcfreq->standby_idle_ns, ddrcon_mhz),
+ RK3399_SET_ODT_PD_0_STANDBY_IDLE);
+ u32p_replace_bits(&odt_pd_arg0,
+ DIV_ROUND_UP(NS_TO_CYCLE(dmcfreq->sr_idle_ns,
+ ddrcon_mhz), 1024),
+ RK3399_SET_ODT_PD_0_SR_IDLE);
+ u32p_replace_bits(&odt_pd_arg0,
+ DIV_ROUND_UP(NS_TO_CYCLE(dmcfreq->sr_mc_gate_idle_ns,
+ ddrcon_mhz), 1024),
+ RK3399_SET_ODT_PD_0_SR_MC_GATE_IDLE);
+ u32p_replace_bits(&odt_pd_arg1,
+ DIV_ROUND_UP(NS_TO_CYCLE(dmcfreq->srpd_lite_idle_ns,
+ ddrcon_mhz), 1024),
+ RK3399_SET_ODT_PD_1_SRPD_LITE_IDLE);
+ if (dmcfreq->regmap_pmu) {
if (target_rate >= dmcfreq->sr_idle_dis_freq)
odt_pd_arg0 &= ~RK3399_SET_ODT_PD_0_SR_IDLE;
@@ -262,16 +292,16 @@ static int rk3399_dmcfreq_of_props(struct rk3399_dmcfreq *data,
data->srpd_lite_idle_dis_freq =
data->standby_idle_dis_freq = UINT_MAX;
- ret |= of_property_read_u32(np, "rockchip,pd_idle",
- &data->pd_idle);
- ret |= of_property_read_u32(np, "rockchip,sr_idle",
- &data->sr_idle);
- ret |= of_property_read_u32(np, "rockchip,sr_mc_gate_idle",
- &data->sr_mc_gate_idle);
- ret |= of_property_read_u32(np, "rockchip,srpd_lite_idle",
- &data->srpd_lite_idle);
- ret |= of_property_read_u32(np, "rockchip,standby_idle",
- &data->standby_idle);
+ ret |= of_property_read_u32(np, "rockchip,pd-idle-ns",
+ &data->pd_idle_ns);
+ ret |= of_property_read_u32(np, "rockchip,sr-idle-ns",
+ &data->sr_idle_ns);
+ ret |= of_property_read_u32(np, "rockchip,sr-mc-gate-idle-ns",
+ &data->sr_mc_gate_idle_ns);
+ ret |= of_property_read_u32(np, "rockchip,srpd-lite-idle-ns",
+ &data->srpd_lite_idle_ns);
+ ret |= of_property_read_u32(np, "rockchip,standby-idle-ns",
+ &data->standby_idle_ns);
ret |= of_property_read_u32(np, "rockchip,ddr3_odt_dis_freq",
&data->ddr3_odt_dis_freq);
ret |= of_property_read_u32(np, "rockchip,lpddr3_odt_dis_freq",
@@ -367,21 +397,6 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
ROCKCHIP_SIP_CONFIG_DRAM_INIT,
0, 0, 0, 0, &res);
- /*
- * In TF-A there is a platform SIP call to set the PD (power-down)
- * timings and to enable or disable the ODT (on-die termination).
- */
- data->odt_pd_arg0 =
- FIELD_PREP(RK3399_SET_ODT_PD_0_SR_IDLE, data->sr_idle) |
- FIELD_PREP(RK3399_SET_ODT_PD_0_SR_MC_GATE_IDLE,
- data->sr_mc_gate_idle) |
- FIELD_PREP(RK3399_SET_ODT_PD_0_STANDBY_IDLE,
- data->standby_idle);
- data->odt_pd_arg1 =
- FIELD_PREP(RK3399_SET_ODT_PD_1_PD_IDLE, data->pd_idle) |
- FIELD_PREP(RK3399_SET_ODT_PD_1_SRPD_LITE_IDLE,
- data->srpd_lite_idle);
-
/*
* We add a devfreq driver to our parent since it has a device tree node
* with operating points.
--
2.35.0.rc0.227.g00780c9af4-goog
^ permalink raw reply related
* [PATCH v2 09/15] PM / devfreq: rk3399_dmc: Support new disable-freq properties
From: Brian Norris @ 2022-01-27 23:07 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring
Cc: linux-kernel, linux-rockchip, Lin Huang, linux-arm-kernel,
Derek Basehore, devicetree, linux-pm, Heiko Stuebner,
Brian Norris
In-Reply-To: <20220127230727.3369358-1-briannorris@chromium.org>
Implement the newly-defined properties to allow disabling certain
power-saving-at-idle features at higher frequencies.
This is a rewritten version of work by Lin Huang <hl@rock-chips.com>.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
(no changes since v1)
drivers/devfreq/rk3399_dmc.c | 51 +++++++++++++++++++++++++++++++++---
1 file changed, 47 insertions(+), 4 deletions(-)
diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c
index c4efbc15cbb1..fc740c1f6747 100644
--- a/drivers/devfreq/rk3399_dmc.c
+++ b/drivers/devfreq/rk3399_dmc.c
@@ -55,6 +55,12 @@ struct rk3399_dmcfreq {
unsigned int ddr3_odt_dis_freq;
unsigned int lpddr3_odt_dis_freq;
unsigned int lpddr4_odt_dis_freq;
+
+ unsigned int pd_idle_dis_freq;
+ unsigned int sr_idle_dis_freq;
+ unsigned int sr_mc_gate_idle_dis_freq;
+ unsigned int srpd_lite_idle_dis_freq;
+ unsigned int standby_idle_dis_freq;
};
static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
@@ -81,8 +87,25 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
mutex_lock(&dmcfreq->lock);
if (dmcfreq->regmap_pmu) {
+ unsigned int odt_pd_arg0 = dmcfreq->odt_pd_arg0;
+ unsigned int odt_pd_arg1 = dmcfreq->odt_pd_arg1;
unsigned int odt_pd_arg2 = 0;
+ if (target_rate >= dmcfreq->sr_idle_dis_freq)
+ odt_pd_arg0 &= ~RK3399_SET_ODT_PD_0_SR_IDLE;
+
+ if (target_rate >= dmcfreq->sr_mc_gate_idle_dis_freq)
+ odt_pd_arg0 &= ~RK3399_SET_ODT_PD_0_SR_MC_GATE_IDLE;
+
+ if (target_rate >= dmcfreq->standby_idle_dis_freq)
+ odt_pd_arg0 &= ~RK3399_SET_ODT_PD_0_STANDBY_IDLE;
+
+ if (target_rate >= dmcfreq->pd_idle_dis_freq)
+ odt_pd_arg1 &= ~RK3399_SET_ODT_PD_1_PD_IDLE;
+
+ if (target_rate >= dmcfreq->srpd_lite_idle_dis_freq)
+ odt_pd_arg1 &= ~RK3399_SET_ODT_PD_1_SRPD_LITE_IDLE;
+
if (target_rate >= dmcfreq->odt_dis_freq)
odt_pd_arg2 |= RK3399_SET_ODT_PD_2_ODT_ENABLE;
@@ -91,10 +114,9 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
* (power-down) timings and to enable or disable the
* ODT (on-die termination) resistors.
*/
- arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, dmcfreq->odt_pd_arg0,
- dmcfreq->odt_pd_arg1,
- ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD,
- odt_pd_arg2, 0, 0, 0, &res);
+ arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, odt_pd_arg0, odt_pd_arg1,
+ ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD, odt_pd_arg2,
+ 0, 0, 0, &res);
}
/*
@@ -230,6 +252,16 @@ static int rk3399_dmcfreq_of_props(struct rk3399_dmcfreq *data,
{
int ret = 0;
+ /*
+ * These are all optional, and serve as minimum bounds. Give them large
+ * (i.e., never "disabled") values if the DT doesn't specify one.
+ */
+ data->pd_idle_dis_freq =
+ data->sr_idle_dis_freq =
+ data->sr_mc_gate_idle_dis_freq =
+ data->srpd_lite_idle_dis_freq =
+ data->standby_idle_dis_freq = UINT_MAX;
+
ret |= of_property_read_u32(np, "rockchip,pd_idle",
&data->pd_idle);
ret |= of_property_read_u32(np, "rockchip,sr_idle",
@@ -247,6 +279,17 @@ static int rk3399_dmcfreq_of_props(struct rk3399_dmcfreq *data,
ret |= of_property_read_u32(np, "rockchip,lpddr4_odt_dis_freq",
&data->lpddr4_odt_dis_freq);
+ ret |= of_property_read_u32(np, "rockchip,pd-idle-dis-freq-hz",
+ &data->pd_idle_dis_freq);
+ ret |= of_property_read_u32(np, "rockchip,sr-idle-dis-freq-hz",
+ &data->sr_idle_dis_freq);
+ ret |= of_property_read_u32(np, "rockchip,sr-mc-gate-idle-dis-freq-hz",
+ &data->sr_mc_gate_idle_dis_freq);
+ ret |= of_property_read_u32(np, "rockchip,srpd-lite-idle-dis-freq-hz",
+ &data->srpd_lite_idle_dis_freq);
+ ret |= of_property_read_u32(np, "rockchip,standby-idle-dis-freq-hz",
+ &data->standby_idle_dis_freq);
+
return ret;
}
--
2.35.0.rc0.227.g00780c9af4-goog
^ permalink raw reply related
* [PATCH v2 08/15] PM / devfreq: rk3399_dmc: Use bitfield macro definitions for ODT_PD
From: Brian Norris @ 2022-01-27 23:07 UTC (permalink / raw)
To: MyungJoo Ham, Kyungmin Park, Chanwoo Choi, Rob Herring
Cc: linux-kernel, linux-rockchip, Lin Huang, linux-arm-kernel,
Derek Basehore, devicetree, linux-pm, Heiko Stuebner,
Brian Norris
In-Reply-To: <20220127230727.3369358-1-briannorris@chromium.org>
We're going to add new usages, and it's cleaner to work with macros
instead of comments and magic numbers.
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
(no changes since v1)
drivers/devfreq/rk3399_dmc.c | 43 ++++++++++++++++++++----------------
1 file changed, 24 insertions(+), 19 deletions(-)
diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c
index 8f447217303f..c4efbc15cbb1 100644
--- a/drivers/devfreq/rk3399_dmc.c
+++ b/drivers/devfreq/rk3399_dmc.c
@@ -5,6 +5,7 @@
*/
#include <linux/arm-smccc.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/devfreq.h>
@@ -23,6 +24,15 @@
#include <soc/rockchip/rk3399_grf.h>
#include <soc/rockchip/rockchip_sip.h>
+#define RK3399_SET_ODT_PD_0_SR_IDLE GENMASK(7, 0)
+#define RK3399_SET_ODT_PD_0_SR_MC_GATE_IDLE GENMASK(15, 8)
+#define RK3399_SET_ODT_PD_0_STANDBY_IDLE GENMASK(31, 16)
+
+#define RK3399_SET_ODT_PD_1_PD_IDLE GENMASK(11, 0)
+#define RK3399_SET_ODT_PD_1_SRPD_LITE_IDLE GENMASK(27, 16)
+
+#define RK3399_SET_ODT_PD_2_ODT_ENABLE BIT(0)
+
struct rk3399_dmcfreq {
struct device *dev;
struct devfreq *devfreq;
@@ -55,7 +65,6 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
unsigned long old_clk_rate = dmcfreq->rate;
unsigned long target_volt, target_rate;
struct arm_smccc_res res;
- bool odt_enable = false;
int err;
opp = devfreq_recommended_opp(dev, freq, flags);
@@ -72,8 +81,10 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
mutex_lock(&dmcfreq->lock);
if (dmcfreq->regmap_pmu) {
+ unsigned int odt_pd_arg2 = 0;
+
if (target_rate >= dmcfreq->odt_dis_freq)
- odt_enable = true;
+ odt_pd_arg2 |= RK3399_SET_ODT_PD_2_ODT_ENABLE;
/*
* This makes a SMC call to the TF-A to set the DDR PD
@@ -83,7 +94,7 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, dmcfreq->odt_pd_arg0,
dmcfreq->odt_pd_arg1,
ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD,
- odt_enable, 0, 0, 0, &res);
+ odt_pd_arg2, 0, 0, 0, &res);
}
/*
@@ -316,23 +327,17 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
/*
* In TF-A there is a platform SIP call to set the PD (power-down)
* timings and to enable or disable the ODT (on-die termination).
- * This call needs three arguments as follows:
- *
- * arg0:
- * bit[0-7] : sr_idle
- * bit[8-15] : sr_mc_gate_idle
- * bit[16-31] : standby idle
- * arg1:
- * bit[0-11] : pd_idle
- * bit[16-27] : srpd_lite_idle
- * arg2:
- * bit[0] : odt enable
*/
- data->odt_pd_arg0 = (data->sr_idle & 0xff) |
- ((data->sr_mc_gate_idle & 0xff) << 8) |
- ((data->standby_idle & 0xffff) << 16);
- data->odt_pd_arg1 = (data->pd_idle & 0xfff) |
- ((data->srpd_lite_idle & 0xfff) << 16);
+ data->odt_pd_arg0 =
+ FIELD_PREP(RK3399_SET_ODT_PD_0_SR_IDLE, data->sr_idle) |
+ FIELD_PREP(RK3399_SET_ODT_PD_0_SR_MC_GATE_IDLE,
+ data->sr_mc_gate_idle) |
+ FIELD_PREP(RK3399_SET_ODT_PD_0_STANDBY_IDLE,
+ data->standby_idle);
+ data->odt_pd_arg1 =
+ FIELD_PREP(RK3399_SET_ODT_PD_1_PD_IDLE, data->pd_idle) |
+ FIELD_PREP(RK3399_SET_ODT_PD_1_SRPD_LITE_IDLE,
+ data->srpd_lite_idle);
/*
* We add a devfreq driver to our parent since it has a device tree node
--
2.35.0.rc0.227.g00780c9af4-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox