summaryrefslogtreecommitdiff
path: root/drivers/soc/imx
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-02-27 21:04:49 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2023-02-27 21:04:49 +0300
commit11c70529983e8136ea1bd5c32e4f9cd14503c644 (patch)
tree8e36f8397a68a4906fd49b72de8c7efb9b0e2a0d /drivers/soc/imx
parentd40b2f4c94f221bd5aab205f945e6f88d3df0929 (diff)
parent524af30c931382726b6a46ee4f392fb6e60f8a03 (diff)
downloadlinux-11c70529983e8136ea1bd5c32e4f9cd14503c644.tar.xz
Merge tag 'soc-drivers-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull ARM SoC driver updates from Arnd Bergmann: "As usual, there are lots of minor driver changes across SoC platforms from NXP, Amlogic, AMD Zynq, Mediatek, Qualcomm, Apple and Samsung. These usually add support for additional chip variations in existing drivers, but also add features or bugfixes. The SCMI firmware subsystem gains a unified raw userspace interface through debugfs, which can be used for validation purposes. Newly added drivers include: - New power management drivers for StarFive JH7110, Allwinner D1 and Renesas RZ/V2M - A driver for Qualcomm battery and power supply status - A SoC device driver for identifying Nuvoton WPCM450 chips - A regulator coupler driver for Mediatek MT81xxv" * tag 'soc-drivers-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (165 commits) power: supply: Introduce Qualcomm PMIC GLINK power supply soc: apple: rtkit: Do not copy the reg state structure to the stack soc: sunxi: SUN20I_PPU should depend on PM memory: renesas-rpc-if: Remove redundant division of dummy soc: qcom: socinfo: Add IDs for IPQ5332 and its variant dt-bindings: arm: qcom,ids: Add IDs for IPQ5332 and its variant dt-bindings: power: qcom,rpmpd: add RPMH_REGULATOR_LEVEL_LOW_SVS_L1 firmware: qcom_scm: Move qcom_scm.h to include/linux/firmware/qcom/ MAINTAINERS: Update qcom CPR maintainer entry dt-bindings: firmware: document Qualcomm SM8550 SCM dt-bindings: firmware: qcom,scm: add qcom,scm-sa8775p compatible soc: qcom: socinfo: Add Soc IDs for IPQ8064 and variants dt-bindings: arm: qcom,ids: Add Soc IDs for IPQ8064 and variants soc: qcom: socinfo: Add support for new field in revision 17 soc: qcom: smd-rpm: Add IPQ9574 compatible soc: qcom: pmic_glink: remove redundant calculation of svid soc: qcom: stats: Populate all subsystem debugfs files dt-bindings: soc: qcom,rpmh-rsc: Update to allow for generic nodes soc: qcom: pmic_glink: add CONFIG_NET/CONFIG_OF dependencies soc: qcom: pmic_glink: Introduce altmode support ...
Diffstat (limited to 'drivers/soc/imx')
-rw-r--r--drivers/soc/imx/Kconfig11
-rw-r--r--drivers/soc/imx/Makefile6
-rw-r--r--drivers/soc/imx/imx8m-blk-ctrl.c27
-rw-r--r--drivers/soc/imx/imx8mp-blk-ctrl.c108
-rw-r--r--drivers/soc/imx/imx93-pd.c1
-rw-r--r--drivers/soc/imx/imx93-src.c1
6 files changed, 143 insertions, 11 deletions
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig
index 4b906791d6c7..a8742fc58f01 100644
--- a/drivers/soc/imx/Kconfig
+++ b/drivers/soc/imx/Kconfig
@@ -28,4 +28,15 @@ config SOC_IMX9
help
If you say yes here, you get support for the NXP i.MX9 family
+config IMX8M_BLK_CTRL
+ bool
+ default SOC_IMX8M && IMX_GPCV2_PM_DOMAINS
+ depends on PM_GENERIC_DOMAINS
+ depends on COMMON_CLK
+
+config IMX9_BLK_CTRL
+ bool
+ default SOC_IMX9 && IMX_GPCV2_PM_DOMAINS
+ depends on PM_GENERIC_DOMAINS
+
endmenu
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
index 7b4099ceafd6..a28c44a1f16a 100644
--- a/drivers/soc/imx/Makefile
+++ b/drivers/soc/imx/Makefile
@@ -5,7 +5,7 @@ endif
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o
-obj-$(CONFIG_SOC_IMX8M) += imx8m-blk-ctrl.o
-obj-$(CONFIG_SOC_IMX8M) += imx8mp-blk-ctrl.o
+obj-$(CONFIG_IMX8M_BLK_CTRL) += imx8m-blk-ctrl.o
+obj-$(CONFIG_IMX8M_BLK_CTRL) += imx8mp-blk-ctrl.o
obj-$(CONFIG_SOC_IMX9) += imx93-src.o imx93-pd.o
-obj-$(CONFIG_SOC_IMX9) += imx93-blk-ctrl.o
+obj-$(CONFIG_IMX9_BLK_CTRL) += imx93-blk-ctrl.o
diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c
index ddcf6be3d8b4..399cb85105a1 100644
--- a/drivers/soc/imx/imx8m-blk-ctrl.c
+++ b/drivers/soc/imx/imx8m-blk-ctrl.c
@@ -4,6 +4,7 @@
* Copyright 2021 Pengutronix, Lucas Stach <kernel@pengutronix.de>
*/
+#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/module.h>
@@ -654,6 +655,10 @@ static const struct imx8m_blk_ctrl_data imx8mn_disp_blk_ctl_dev_data = {
.num_domains = ARRAY_SIZE(imx8mn_disp_blk_ctl_domain_data),
};
+#define LCDIF_ARCACHE_CTRL 0x4c
+#define LCDIF_1_RD_HURRY GENMASK(15, 13)
+#define LCDIF_0_RD_HURRY GENMASK(12, 10)
+
static int imx8mp_media_power_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -667,14 +672,24 @@ static int imx8mp_media_power_notifier(struct notifier_block *nb,
regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8));
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8));
- /*
- * On power up we have no software backchannel to the GPC to
- * wait for the ADB handshake to happen, so we just delay for a
- * bit. On power down the GPC driver waits for the handshake.
- */
- if (action == GENPD_NOTIFY_ON)
+ if (action == GENPD_NOTIFY_ON) {
+ /*
+ * On power up we have no software backchannel to the GPC to
+ * wait for the ADB handshake to happen, so we just delay for a
+ * bit. On power down the GPC driver waits for the handshake.
+ */
udelay(5);
+ /*
+ * Set panic read hurry level for both LCDIF interfaces to
+ * maximum priority to minimize chances of display FIFO
+ * underflow.
+ */
+ regmap_set_bits(bc->regmap, LCDIF_ARCACHE_CTRL,
+ FIELD_PREP(LCDIF_1_RD_HURRY, 7) |
+ FIELD_PREP(LCDIF_0_RD_HURRY, 7));
+ }
+
return NOTIFY_OK;
}
diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c
index 0f13853901df..a0592db8fa86 100644
--- a/drivers/soc/imx/imx8mp-blk-ctrl.c
+++ b/drivers/soc/imx/imx8mp-blk-ctrl.c
@@ -4,7 +4,9 @@
* Copyright 2022 Pengutronix, Lucas Stach <kernel@pengutronix.de>
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/module.h>
@@ -21,6 +23,15 @@
#define USB_CLOCK_MODULE_EN BIT(1)
#define PCIE_PHY_APB_RST BIT(4)
#define PCIE_PHY_INIT_RST BIT(5)
+#define GPR_REG1 0x4
+#define PLL_LOCK BIT(13)
+#define GPR_REG2 0x8
+#define P_PLL_MASK GENMASK(5, 0)
+#define M_PLL_MASK GENMASK(15, 6)
+#define S_PLL_MASK GENMASK(18, 16)
+#define GPR_REG3 0xc
+#define PLL_CKE BIT(17)
+#define PLL_RST BIT(31)
struct imx8mp_blk_ctrl_domain;
@@ -60,6 +71,7 @@ struct imx8mp_blk_ctrl_domain {
struct imx8mp_blk_ctrl_data {
int max_reg;
+ int (*probe) (struct imx8mp_blk_ctrl *bc);
notifier_fn_t power_notifier_fn;
void (*power_off) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
void (*power_on) (struct imx8mp_blk_ctrl *bc, struct imx8mp_blk_ctrl_domain *domain);
@@ -73,6 +85,92 @@ to_imx8mp_blk_ctrl_domain(struct generic_pm_domain *genpd)
return container_of(genpd, struct imx8mp_blk_ctrl_domain, genpd);
}
+struct clk_hsio_pll {
+ struct clk_hw hw;
+ struct regmap *regmap;
+};
+
+static inline struct clk_hsio_pll *to_clk_hsio_pll(struct clk_hw *hw)
+{
+ return container_of(hw, struct clk_hsio_pll, hw);
+}
+
+static int clk_hsio_pll_prepare(struct clk_hw *hw)
+{
+ struct clk_hsio_pll *clk = to_clk_hsio_pll(hw);
+ u32 val;
+
+ /* set the PLL configuration */
+ regmap_update_bits(clk->regmap, GPR_REG2,
+ P_PLL_MASK | M_PLL_MASK | S_PLL_MASK,
+ FIELD_PREP(P_PLL_MASK, 12) |
+ FIELD_PREP(M_PLL_MASK, 800) |
+ FIELD_PREP(S_PLL_MASK, 4));
+
+ /* de-assert PLL reset */
+ regmap_update_bits(clk->regmap, GPR_REG3, PLL_RST, PLL_RST);
+
+ /* enable PLL */
+ regmap_update_bits(clk->regmap, GPR_REG3, PLL_CKE, PLL_CKE);
+
+ return regmap_read_poll_timeout(clk->regmap, GPR_REG1, val,
+ val & PLL_LOCK, 10, 100);
+}
+
+static void clk_hsio_pll_unprepare(struct clk_hw *hw)
+{
+ struct clk_hsio_pll *clk = to_clk_hsio_pll(hw);
+
+ regmap_update_bits(clk->regmap, GPR_REG3, PLL_RST | PLL_CKE, 0);
+}
+
+static int clk_hsio_pll_is_prepared(struct clk_hw *hw)
+{
+ struct clk_hsio_pll *clk = to_clk_hsio_pll(hw);
+
+ return regmap_test_bits(clk->regmap, GPR_REG1, PLL_LOCK);
+}
+
+static unsigned long clk_hsio_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return 100000000;
+}
+
+static const struct clk_ops clk_hsio_pll_ops = {
+ .prepare = clk_hsio_pll_prepare,
+ .unprepare = clk_hsio_pll_unprepare,
+ .is_prepared = clk_hsio_pll_is_prepared,
+ .recalc_rate = clk_hsio_pll_recalc_rate,
+};
+
+static int imx8mp_hsio_blk_ctrl_probe(struct imx8mp_blk_ctrl *bc)
+{
+ struct clk_hsio_pll *clk_hsio_pll;
+ struct clk_hw *hw;
+ struct clk_init_data init = {};
+ int ret;
+
+ clk_hsio_pll = devm_kzalloc(bc->dev, sizeof(*clk_hsio_pll), GFP_KERNEL);
+ if (!clk_hsio_pll)
+ return -ENOMEM;
+
+ init.name = "hsio_pll";
+ init.ops = &clk_hsio_pll_ops;
+ init.parent_names = (const char *[]){"osc_24m"};
+ init.num_parents = 1;
+
+ clk_hsio_pll->regmap = bc->regmap;
+ clk_hsio_pll->hw.init = &init;
+
+ hw = &clk_hsio_pll->hw;
+ ret = devm_clk_hw_register(bc->dev, hw);
+ if (ret)
+ return ret;
+
+ return devm_of_clk_add_hw_provider(bc->dev, of_clk_hw_simple_get, hw);
+}
+
static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
struct imx8mp_blk_ctrl_domain *domain)
{
@@ -187,6 +285,7 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
.max_reg = 0x24,
+ .probe = imx8mp_hsio_blk_ctrl_probe,
.power_on = imx8mp_hsio_blk_ctrl_power_on,
.power_off = imx8mp_hsio_blk_ctrl_power_off,
.power_notifier_fn = imx8mp_hsio_power_notifier,
@@ -201,6 +300,7 @@ static const struct imx8mp_blk_ctrl_data imx8mp_hsio_blk_ctl_dev_data = {
#define HDMI_RTX_CLK_CTL3 0x70
#define HDMI_RTX_CLK_CTL4 0x80
#define HDMI_TX_CONTROL0 0x200
+#define HDMI_LCDIF_NOC_HURRY_MASK GENMASK(14, 12)
static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
struct imx8mp_blk_ctrl_domain *domain)
@@ -217,6 +317,8 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(11));
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0,
BIT(4) | BIT(5) | BIT(6));
+ regmap_set_bits(bc->regmap, HDMI_TX_CONTROL0,
+ FIELD_PREP(HDMI_LCDIF_NOC_HURRY_MASK, 7));
break;
case IMX8MP_HDMIBLK_PD_PAI:
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(17));
@@ -635,6 +737,12 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
goto cleanup_provider;
}
+ if (bc_data->probe) {
+ ret = bc_data->probe(bc);
+ if (ret)
+ goto cleanup_provider;
+ }
+
dev_set_drvdata(dev, bc);
return 0;
diff --git a/drivers/soc/imx/imx93-pd.c b/drivers/soc/imx/imx93-pd.c
index 4d235c8c4924..832deeed8fd6 100644
--- a/drivers/soc/imx/imx93-pd.c
+++ b/drivers/soc/imx/imx93-pd.c
@@ -164,7 +164,6 @@ MODULE_DEVICE_TABLE(of, imx93_pd_ids);
static struct platform_driver imx93_power_domain_driver = {
.driver = {
.name = "imx93_power_domain",
- .owner = THIS_MODULE,
.of_match_table = imx93_pd_ids,
},
.probe = imx93_pd_probe,
diff --git a/drivers/soc/imx/imx93-src.c b/drivers/soc/imx/imx93-src.c
index 4d74921cae0f..f1c2e22d5cbd 100644
--- a/drivers/soc/imx/imx93-src.c
+++ b/drivers/soc/imx/imx93-src.c
@@ -21,7 +21,6 @@ MODULE_DEVICE_TABLE(of, imx93_src_ids);
static struct platform_driver imx93_src_driver = {
.driver = {
.name = "imx93_src",
- .owner = THIS_MODULE,
.of_match_table = imx93_src_ids,
},
.probe = imx93_src_probe,