Subject: [PATCH v5 0/4] mmc: sdhci-of-arasan: Enable UHS-1 support for Keem Bay SOC

From: Muhammad Husaini Zulkifli <[email protected]>

Hi.

The first patch is the header file to handle ATF call.

The second patch is DT binding for arasan controller for uhs support.

The third patch is to introduce the structure device pointer in arasan controller probe.

The fourth patch is to enable UHS-1 Support for Keem Bay EVM.

All of these patches was tested with Keem Bay evaluation module board.

Kindly help to review this patch set.

Thank you.

Changes since v4:
- Fixed comment by Andy and Sudeep on first patch.
- Add Acked-by tag.
- Fixed comment by Michal and Andy on the third patch to replace current users of &pdev->dev.

Changes since v3:
- Add Dt bindings for uhs gpio.
- Fixed comment by Michal and Sudeep on header file for the macro and error code.
- Fixed comment by Andy and created 1 new patch to separate the struc dev pointer in probe func.
- Fixed comment by Michal in arasan controller code.

Changes since v2:
- Removed Document DT Bindings for Keembay Firmware.
- Removed Firmware Driver to handle ATF Service call.
- Add header file to handle API function for device driver to communicate with Arm Trusted Firmware.

Changes since v1:
- Add Document DT Bindings for Keembay Firmware.
- Created Firmware Driver to handle ATF Service call
- Provide API for arasan driver for sd card voltage changes

Muhammad Husaini Zulkifli (4):
firmware: keembay: Add support for Trusted Firmware Service call
dt-bindings: mmc: Add uhs-gpio for Keem Bay UHS-1 Support
mmc: sdhci-of-arasan: Add structure device pointer in probe
mmc: sdhci-of-arasan: Enable UHS-1 support for Keem Bay SOC

.../devicetree/bindings/mmc/arasan,sdhci.yaml | 8 +-
drivers/mmc/host/sdhci-of-arasan.c | 163 ++++++++++++++++--
include/linux/firmware/intel/keembay.h | 47 +++++
3 files changed, 199 insertions(+), 19 deletions(-)
create mode 100644 include/linux/firmware/intel/keembay.h

--
2.17.1


Subject: [PATCH v5 1/4] firmware: keembay: Add support for Trusted Firmware Service call

From: Muhammad Husaini Zulkifli <[email protected]>

Add header file to handle API function for device driver to
communicate with Trusted Firmware - A profile(TF-A)
or Trusted Firmware - M profile (TF-M).

Signed-off-by: Muhammad Husaini Zulkifli <[email protected]>
Acked-by: Michal Simek <[email protected]>
Acked-by: Sudeep Holla <[email protected]>
---
include/linux/firmware/intel/keembay.h | 47 ++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 include/linux/firmware/intel/keembay.h

diff --git a/include/linux/firmware/intel/keembay.h b/include/linux/firmware/intel/keembay.h
new file mode 100644
index 000000000000..363e6bf2c27a
--- /dev/null
+++ b/include/linux/firmware/intel/keembay.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Intel Keembay SOC Firmware API Layer
+ *
+ * Copyright (C) 2020, Intel Corporation
+ *
+ * Author: Muhammad Husaini Zulkifli <[email protected]>
+ */
+
+#ifndef __FIRMWARE_KEEMBAY_SMC_H__
+#define __FIRMWARE_KEEMBAY_SMC_H__
+
+#include <linux/arm-smccc.h>
+
+/*
+ * This file defines an API function that can be called by a device driver in order to
+ * communicate with Trusted Firmware - A profile(TF-A) or Trusted Firmware - M profile (TF-M).
+ */
+
+/* Setting for Keem Bay IO Pad Line Voltage Selection */
+#define ARM_SMCCC_SIP_KEEMBAY_SET_SD_VOLTAGE \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_32, \
+ ARM_SMCCC_OWNER_SIP, \
+ 0xFF26)
+
+#define KEEMBAY_SET_1V8_VOLT 1
+#define KEEMBAY_SET_3V3_VOLT 0
+
+#if IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY)
+static inline int keembay_sd_voltage_selection(int volt)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_SIP_KEEMBAY_SET_SD_VOLTAGE, volt, &res);
+ if ((int)res.a0 < 0)
+ return -EINVAL;
+
+ return 0;
+}
+#else
+static inline int keembay_sd_voltage_selection(int volt)
+{
+ return -ENODEV;
+}
+#endif
+#endif /* __FIRMWARE_KEEMBAY_SMC_H__ */
--
2.17.1

Subject: [PATCH v5 2/4] dt-bindings: mmc: Add uhs-gpio for Keem Bay UHS-1 Support

From: Muhammad Husaini Zulkifli <[email protected]>

Add DT bindings of uhs-gpio for Keem Bay SOC UHS Mode Support

Signed-off-by: Muhammad Husaini Zulkifli <[email protected]>
Acked-by: Michal Simek <[email protected]>
---
Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
index 58fe9d02a781..320566a673f0 100644
--- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
@@ -83,7 +83,7 @@ properties:
- const: intel,keembay-sdhci-5.1-sd # Intel Keem Bay SD controller
description:
For this device it is strongly suggested to include
- arasan,soc-ctl-syscon.
+ arasan,soc-ctl-syscon and uhs-gpio.
- const: intel,keembay-sdhci-5.1-sdio # Intel Keem Bay SDIO controller
description:
For this device it is strongly suggested to include
@@ -152,6 +152,11 @@ properties:
description:
The MIO bank number in which the command and data lines are configured.

+ uhs-gpio:
+ description:
+ The power mux input will be configure using the GPIO provided
+ to generate either 1.8v or 3.3v output.
+
dependencies:
clock-output-names: [ '#clock-cells' ]
'#clock-cells': [ clock-output-names ]
@@ -300,4 +305,5 @@ examples:
clocks = <&scmi_clk KEEM_BAY_PSS_AUX_SD0>,
<&scmi_clk KEEM_BAY_PSS_SD0>;
arasan,soc-ctl-syscon = <&sd0_phy_syscon>;
+ uhs-gpio = <&pca0 17 0>;
};
--
2.17.1

Subject: [PATCH v5 3/4] mmc: sdhci-of-arasan: Add structure device pointer in probe

From: Muhammad Husaini Zulkifli <[email protected]>

Add struct device *dev in probe func() so that it can widely use in
probe to make code more readable.

Signed-off-by: Muhammad Husaini Zulkifli <[email protected]>
---
drivers/mmc/host/sdhci-of-arasan.c | 37 +++++++++++++++---------------
1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index f186fbd016b1..6a9412dee975 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -1521,9 +1521,10 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_arasan_data *sdhci_arasan;
struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
const struct sdhci_arasan_of_data *data;

- match = of_match_node(sdhci_arasan_of_match, pdev->dev.of_node);
+ match = of_match_node(sdhci_arasan_of_match, dev->of_node);
data = match->data;
host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan));

@@ -1537,7 +1538,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
sdhci_arasan->soc_ctl_map = data->soc_ctl_map;
sdhci_arasan->clk_ops = data->clk_ops;

- node = of_parse_phandle(pdev->dev.of_node, "arasan,soc-ctl-syscon", 0);
+ node = of_parse_phandle(dev->of_node, "arasan,soc-ctl-syscon", 0);
if (node) {
sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node);
of_node_put(node);
@@ -1545,35 +1546,35 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
ret = PTR_ERR(sdhci_arasan->soc_ctl_base);
if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Can't get syscon: %d\n",
+ dev_err(dev, "Can't get syscon: %d\n",
ret);
goto err_pltfm_free;
}
}

- sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb");
+ sdhci_arasan->clk_ahb = devm_clk_get(dev, "clk_ahb");
if (IS_ERR(sdhci_arasan->clk_ahb)) {
- dev_err(&pdev->dev, "clk_ahb clock not found.\n");
+ dev_err(dev, "clk_ahb clock not found.\n");
ret = PTR_ERR(sdhci_arasan->clk_ahb);
goto err_pltfm_free;
}

- clk_xin = devm_clk_get(&pdev->dev, "clk_xin");
+ clk_xin = devm_clk_get(dev, "clk_xin");
if (IS_ERR(clk_xin)) {
- dev_err(&pdev->dev, "clk_xin clock not found.\n");
+ dev_err(dev, "clk_xin clock not found.\n");
ret = PTR_ERR(clk_xin);
goto err_pltfm_free;
}

ret = clk_prepare_enable(sdhci_arasan->clk_ahb);
if (ret) {
- dev_err(&pdev->dev, "Unable to enable AHB clock.\n");
+ dev_err(dev, "Unable to enable AHB clock.\n");
goto err_pltfm_free;
}

ret = clk_prepare_enable(clk_xin);
if (ret) {
- dev_err(&pdev->dev, "Unable to enable SD clock.\n");
+ dev_err(dev, "Unable to enable SD clock.\n");
goto clk_dis_ahb;
}

@@ -1587,7 +1588,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)

pltfm_host->clk = clk_xin;

- if (of_device_is_compatible(pdev->dev.of_node,
+ if (of_device_is_compatible(dev->of_node,
"rockchip,rk3399-sdhci-5.1"))
sdhci_arasan_update_clockmultiplier(host, 0x0);

@@ -1602,7 +1603,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)

sdhci_arasan_update_baseclkfreq(host);

- ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, &pdev->dev);
+ ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, dev);
if (ret)
goto clk_disable_all;

@@ -1611,29 +1612,29 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
arasan_zynqmp_execute_tuning;
}

- arasan_dt_parse_clk_phases(&pdev->dev, &sdhci_arasan->clk_data);
+ arasan_dt_parse_clk_phases(dev, &sdhci_arasan->clk_data);

ret = mmc_of_parse(host->mmc);
if (ret) {
if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret);
+ dev_err(dev, "parsing dt failed (%d)\n", ret);
goto unreg_clk;
}

sdhci_arasan->phy = ERR_PTR(-ENODEV);
- if (of_device_is_compatible(pdev->dev.of_node,
+ if (of_device_is_compatible(dev->of_node,
"arasan,sdhci-5.1")) {
- sdhci_arasan->phy = devm_phy_get(&pdev->dev,
+ sdhci_arasan->phy = devm_phy_get(dev,
"phy_arasan");
if (IS_ERR(sdhci_arasan->phy)) {
ret = PTR_ERR(sdhci_arasan->phy);
- dev_err(&pdev->dev, "No phy for arasan,sdhci-5.1.\n");
+ dev_err(dev, "No phy for arasan,sdhci-5.1.\n");
goto unreg_clk;
}

ret = phy_init(sdhci_arasan->phy);
if (ret < 0) {
- dev_err(&pdev->dev, "phy_init err.\n");
+ dev_err(dev, "phy_init err.\n");
goto unreg_clk;
}

@@ -1658,7 +1659,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
if (!IS_ERR(sdhci_arasan->phy))
phy_exit(sdhci_arasan->phy);
unreg_clk:
- sdhci_arasan_unregister_sdclk(&pdev->dev);
+ sdhci_arasan_unregister_sdclk(dev);
clk_disable_all:
clk_disable_unprepare(clk_xin);
clk_dis_ahb:
--
2.17.1

Subject: [PATCH v5 4/4] mmc: sdhci-of-arasan: Enable UHS-1 support for Keem Bay SOC

From: Muhammad Husaini Zulkifli <[email protected]>

Voltage switching sequence is needed to support UHS-1 interface.
There are 2 places to control the voltage.
1) By setting the AON register using firmware driver calling
system-level platform management layer (SMC) to set the register.
2) By controlling the GPIO expander value to drive either 1.8V or 3.3V
for power mux input.

Signed-off-by: Muhammad Husaini Zulkifli <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
Reviewed-by: Adrian Hunter <[email protected]>
Acked-by: Michal Simek <[email protected]>
---
drivers/mmc/host/sdhci-of-arasan.c | 126 +++++++++++++++++++++++++++++
1 file changed, 126 insertions(+)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 6a9412dee975..7b19de53e96d 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -16,6 +16,7 @@
*/

#include <linux/clk-provider.h>
+#include <linux/gpio/consumer.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -23,6 +24,7 @@
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/firmware/xlnx-zynqmp.h>
+#include <linux/firmware/intel/keembay.h>

#include "cqhci.h"
#include "sdhci-pltfm.h"
@@ -136,6 +138,7 @@ struct sdhci_arasan_clk_data {
* @soc_ctl_base: Pointer to regmap for syscon for soc_ctl registers.
* @soc_ctl_map: Map to get offsets into soc_ctl registers.
* @quirks: Arasan deviations from spec.
+ * @uhs_gpio: Pointer to the uhs gpio.
*/
struct sdhci_arasan_data {
struct sdhci_host *host;
@@ -150,6 +153,7 @@ struct sdhci_arasan_data {
struct regmap *soc_ctl_base;
const struct sdhci_arasan_soc_ctl_map *soc_ctl_map;
unsigned int quirks;
+ struct gpio_desc *uhs_gpio;

/* Controller does not have CD wired and will not function normally without */
#define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0)
@@ -361,6 +365,112 @@ static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
return -EINVAL;
}

+static int sdhci_arasan_keembay_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
+ u16 ctrl_2, clk;
+ int ret;
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_180:
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ if (clk & SDHCI_CLOCK_CARD_EN)
+ return -EAGAIN;
+
+ sdhci_writeb(host, SDHCI_POWER_ON | SDHCI_POWER_180,
+ SDHCI_POWER_CONTROL);
+
+ /*
+ * Set VDDIO_B voltage to Low for 1.8V
+ * which is controlling by GPIO Expander.
+ */
+ gpiod_set_value_cansleep(sdhci_arasan->uhs_gpio, 0);
+
+ /*
+ * This is like a final gatekeeper. Need to ensure changed voltage
+ * is settled before and after turn on this bit.
+ */
+ usleep_range(1000, 1100);
+
+ ret = keembay_sd_voltage_selection(KEEMBAY_SET_1V8_VOLT);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 1100);
+
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl_2 |= SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+ /* Sleep for 5ms to stabilize 1.8V regulator */
+ usleep_range(5000, 5500);
+
+ /* 1.8V regulator output should be stable within 5 ms */
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (!(ctrl_2 & SDHCI_CTRL_VDD_180))
+ return -EAGAIN;
+
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+ break;
+ case MMC_SIGNAL_VOLTAGE_330:
+ /*
+ * Set VDDIO_B voltage to High for 3.3V
+ * which is controlling by GPIO Expander.
+ */
+ gpiod_set_value_cansleep(sdhci_arasan->uhs_gpio, 1);
+
+ /*
+ * This is like a final gatekeeper. Need to ensure changed voltage
+ * is settled before and after turn on this bit.
+ */
+ usleep_range(1000, 1100);
+
+ ret = keembay_sd_voltage_selection(KEEMBAY_SET_3V3_VOLT);
+ if (ret)
+ return ret;
+
+ usleep_range(1000, 1100);
+
+ /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl_2 &= ~SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+
+ /* Sleep for 5ms to stabilize 3.3V regulator */
+ usleep_range(5000, 5500);
+
+ /* 3.3V regulator output should be stable within 5 ms */
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (ctrl_2 & SDHCI_CTRL_VDD_180)
+ return -EAGAIN;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sdhci_arasan_keembay_select_drive_strength(struct mmc_card *card,
+ unsigned int max_dtr, int host_drv,
+ int card_drv, int *drv_type)
+{
+ if (card->host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_180)
+ *drv_type = MMC_SET_DRIVER_TYPE_C;
+
+ return 0;
+}
+
static const struct sdhci_ops sdhci_arasan_ops = {
.set_clock = sdhci_arasan_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
@@ -1601,6 +1711,22 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
}

+ if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd")) {
+ struct gpio_desc *uhs;
+
+ uhs = devm_gpiod_get_optional(dev, "uhs", GPIOD_OUT_HIGH);
+ if (IS_ERR(uhs))
+ return dev_err_probe(dev, PTR_ERR(uhs), "can't get uhs gpio\n");
+
+ sdhci_arasan->uhs_gpio = uhs;
+
+ host->mmc_host_ops.start_signal_voltage_switch =
+ sdhci_arasan_keembay_voltage_switch;
+
+ host->mmc_host_ops.select_drive_strength =
+ sdhci_arasan_keembay_select_drive_strength;
+ }
+
sdhci_arasan_update_baseclkfreq(host);

ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, dev);
--
2.17.1

2020-10-09 13:50:48

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v5 0/4] mmc: sdhci-of-arasan: Enable UHS-1 support for Keem Bay SOC

On Fri, Oct 09, 2020 at 02:18:40AM +0800, [email protected] wrote:
> From: Muhammad Husaini Zulkifli <[email protected]>
>
> Hi.
>
> The first patch is the header file to handle ATF call.
>
> The second patch is DT binding for arasan controller for uhs support.
>
> The third patch is to introduce the structure device pointer in arasan controller probe.
>
> The fourth patch is to enable UHS-1 Support for Keem Bay EVM.
>
> All of these patches was tested with Keem Bay evaluation module board.
>
> Kindly help to review this patch set.

It seems that this is no go for Ulf until you switch to vqmmc GPIO regulators.

--
With Best Regards,
Andy Shevchenko