i.MX drivers change for 5.2:
- A series from Aisheng to generalize the SCU powerdomain driver for easier adding new SCU based platforms like imx8qm. - Add a generic i.MX8 SoC driver for reporting SoC and platform information. - Replace explicit polling loop with a call to regmap_read_poll_timeout() for gpcv2 driver to avoid code repetition. - Use devm_platform_ioremap_resource() to simplify gpc/gpcv2 driver code a bit. - Add general IRQ support for imx-scu driver, so that interrupt of device like RTC, thermal and watchdog can be handled. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJcvWKIAAoJEFBXWFqHsHzOeCQH/j/lgujJU9RnyY2CFTelMyad uTKEUgk2vvbswBdFMaS7xAvbni24GOxUdKUYJul0oz5jBnK4wKmf6VY7TYMQ8Qht hsdp0dsHHgI1qysOiOSxidhIN/2aXFl/hSoF8FT/9m0qXqnmvoHGFQT0YoMGwznS +7tHuUt5cjUG/r5DMM6GOzI/w6K1of6RGGsLWvYeuy7OeoDhI2Gl5gtK+qxik98J qC9UM64jO93rmXebJuG+9ZNJ0FFATrBMboMB3a7rA3t9RvkAFKEuVRp3USPuj1ek TxNusTtkQwCeujy9QZu/eB/oUrScEbzJuw+sp0l69C9T2D44ucZLFbHixnwbigM= =1wlN -----END PGP SIGNATURE----- Merge tag 'imx-drivers-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into arm/drivers i.MX drivers change for 5.2: - A series from Aisheng to generalize the SCU powerdomain driver for easier adding new SCU based platforms like imx8qm. - Add a generic i.MX8 SoC driver for reporting SoC and platform information. - Replace explicit polling loop with a call to regmap_read_poll_timeout() for gpcv2 driver to avoid code repetition. - Use devm_platform_ioremap_resource() to simplify gpc/gpcv2 driver code a bit. - Add general IRQ support for imx-scu driver, so that interrupt of device like RTC, thermal and watchdog can be handled. * tag 'imx-drivers-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux: soc: imx: Add generic i.MX8 SoC driver firmware: imx: enable imx scu general irq function soc: imx: gpcv2: use devm_platform_ioremap_resource() to simplify code soc: imx: gpc: use devm_platform_ioremap_resource() to simplify code firmware: imx: scu-pd: decouple the SS information from domain names firmware: imx: scu-pd: add specifying the base of domain name index support firmware: imx: scu-pd: use bool to set postfix soc: imx: gpcv2: Make use of regmap_read_poll_timeout() Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
f99552d9eb
|
@ -1,3 +1,3 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o
|
||||
obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o
|
||||
obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*
|
||||
* Implementation of the SCU IRQ functions using MU.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
#include <linux/firmware/imx/ipc.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
|
||||
#define IMX_SC_IRQ_FUNC_ENABLE 1
|
||||
#define IMX_SC_IRQ_FUNC_STATUS 2
|
||||
#define IMX_SC_IRQ_NUM_GROUP 4
|
||||
|
||||
static u32 mu_resource_id;
|
||||
|
||||
struct imx_sc_msg_irq_get_status {
|
||||
struct imx_sc_rpc_msg hdr;
|
||||
union {
|
||||
struct {
|
||||
u16 resource;
|
||||
u8 group;
|
||||
u8 reserved;
|
||||
} __packed req;
|
||||
struct {
|
||||
u32 status;
|
||||
} resp;
|
||||
} data;
|
||||
};
|
||||
|
||||
struct imx_sc_msg_irq_enable {
|
||||
struct imx_sc_rpc_msg hdr;
|
||||
u32 mask;
|
||||
u16 resource;
|
||||
u8 group;
|
||||
u8 enable;
|
||||
} __packed;
|
||||
|
||||
static struct imx_sc_ipc *imx_sc_irq_ipc_handle;
|
||||
static struct work_struct imx_sc_irq_work;
|
||||
static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain);
|
||||
|
||||
int imx_scu_irq_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_register(
|
||||
&imx_scu_irq_notifier_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_scu_irq_register_notifier);
|
||||
|
||||
int imx_scu_irq_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_unregister(
|
||||
&imx_scu_irq_notifier_chain, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_scu_irq_unregister_notifier);
|
||||
|
||||
static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group)
|
||||
{
|
||||
return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain,
|
||||
status, (void *)group);
|
||||
}
|
||||
|
||||
static void imx_scu_irq_work_handler(struct work_struct *work)
|
||||
{
|
||||
struct imx_sc_msg_irq_get_status msg;
|
||||
struct imx_sc_rpc_msg *hdr = &msg.hdr;
|
||||
u32 irq_status;
|
||||
int ret;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) {
|
||||
hdr->ver = IMX_SC_RPC_VERSION;
|
||||
hdr->svc = IMX_SC_RPC_SVC_IRQ;
|
||||
hdr->func = IMX_SC_IRQ_FUNC_STATUS;
|
||||
hdr->size = 2;
|
||||
|
||||
msg.data.req.resource = mu_resource_id;
|
||||
msg.data.req.group = i;
|
||||
|
||||
ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
|
||||
if (ret) {
|
||||
pr_err("get irq group %d status failed, ret %d\n",
|
||||
i, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
irq_status = msg.data.resp.status;
|
||||
if (!irq_status)
|
||||
continue;
|
||||
|
||||
imx_scu_irq_notifier_call_chain(irq_status, &i);
|
||||
}
|
||||
}
|
||||
|
||||
int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable)
|
||||
{
|
||||
struct imx_sc_msg_irq_enable msg;
|
||||
struct imx_sc_rpc_msg *hdr = &msg.hdr;
|
||||
int ret;
|
||||
|
||||
hdr->ver = IMX_SC_RPC_VERSION;
|
||||
hdr->svc = IMX_SC_RPC_SVC_IRQ;
|
||||
hdr->func = IMX_SC_IRQ_FUNC_ENABLE;
|
||||
hdr->size = 3;
|
||||
|
||||
msg.resource = mu_resource_id;
|
||||
msg.group = group;
|
||||
msg.mask = mask;
|
||||
msg.enable = enable;
|
||||
|
||||
ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
|
||||
if (ret)
|
||||
pr_err("enable irq failed, group %d, mask %d, ret %d\n",
|
||||
group, mask, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(imx_scu_irq_group_enable);
|
||||
|
||||
static void imx_scu_irq_callback(struct mbox_client *c, void *msg)
|
||||
{
|
||||
schedule_work(&imx_sc_irq_work);
|
||||
}
|
||||
|
||||
int imx_scu_enable_general_irq_channel(struct device *dev)
|
||||
{
|
||||
struct of_phandle_args spec;
|
||||
struct mbox_client *cl;
|
||||
struct mbox_chan *ch;
|
||||
int ret = 0, i = 0;
|
||||
|
||||
ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cl = devm_kzalloc(dev, sizeof(*cl), GFP_KERNEL);
|
||||
if (!cl)
|
||||
return -ENOMEM;
|
||||
|
||||
cl->dev = dev;
|
||||
cl->rx_callback = imx_scu_irq_callback;
|
||||
|
||||
/* SCU general IRQ uses general interrupt channel 3 */
|
||||
ch = mbox_request_channel_byname(cl, "gip3");
|
||||
if (IS_ERR(ch)) {
|
||||
ret = PTR_ERR(ch);
|
||||
dev_err(dev, "failed to request mbox chan gip3, ret %d\n", ret);
|
||||
devm_kfree(dev, cl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler);
|
||||
|
||||
if (!of_parse_phandle_with_args(dev->of_node, "mboxes",
|
||||
"#mbox-cells", 0, &spec))
|
||||
i = of_alias_get_id(spec.np, "mu");
|
||||
|
||||
/* use mu1 as general mu irq channel if failed */
|
||||
if (i < 0)
|
||||
i = 1;
|
||||
|
||||
mu_resource_id = IMX_SC_R_MU_0A + i;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(imx_scu_enable_general_irq_channel);
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/firmware/imx/types.h>
|
||||
#include <linux/firmware/imx/ipc.h>
|
||||
#include <linux/firmware/imx/sci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -246,6 +247,11 @@ static int imx_scu_probe(struct platform_device *pdev)
|
|||
|
||||
imx_sc_ipc_handle = sc_ipc;
|
||||
|
||||
ret = imx_scu_enable_general_irq_channel(dev);
|
||||
if (ret)
|
||||
dev_warn(dev,
|
||||
"failed to enable general irq channel: %d\n", ret);
|
||||
|
||||
dev_info(dev, "NXP i.MX SCU Initialized\n");
|
||||
|
||||
return devm_of_platform_populate(dev);
|
||||
|
|
|
@ -74,7 +74,10 @@ struct imx_sc_pd_range {
|
|||
char *name;
|
||||
u32 rsrc;
|
||||
u8 num;
|
||||
|
||||
/* add domain index */
|
||||
bool postfix;
|
||||
u8 start_from;
|
||||
};
|
||||
|
||||
struct imx_sc_pd_soc {
|
||||
|
@ -84,71 +87,75 @@ struct imx_sc_pd_soc {
|
|||
|
||||
static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
|
||||
/* LSIO SS */
|
||||
{ "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 },
|
||||
{ "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 },
|
||||
{ "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 },
|
||||
{ "lsio-kpp", IMX_SC_R_KPP, 1, 0 },
|
||||
{ "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 },
|
||||
{ "lsio-mu", IMX_SC_R_MU_0A, 14, 1 },
|
||||
{ "pwm", IMX_SC_R_PWM_0, 8, true, 0 },
|
||||
{ "gpio", IMX_SC_R_GPIO_0, 8, true, 0 },
|
||||
{ "gpt", IMX_SC_R_GPT_0, 5, true, 0 },
|
||||
{ "kpp", IMX_SC_R_KPP, 1, false, 0 },
|
||||
{ "fspi", IMX_SC_R_FSPI_0, 2, true, 0 },
|
||||
{ "mu", IMX_SC_R_MU_0A, 14, true, 0 },
|
||||
|
||||
/* CONN SS */
|
||||
{ "con-usb", IMX_SC_R_USB_0, 2, 1 },
|
||||
{ "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 },
|
||||
{ "con-usb2", IMX_SC_R_USB_2, 1, 0 },
|
||||
{ "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 },
|
||||
{ "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 },
|
||||
{ "con-enet", IMX_SC_R_ENET_0, 2, 1 },
|
||||
{ "con-nand", IMX_SC_R_NAND, 1, 0 },
|
||||
{ "con-mlb", IMX_SC_R_MLB_0, 1, 1 },
|
||||
{ "usb", IMX_SC_R_USB_0, 2, true, 0 },
|
||||
{ "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 },
|
||||
{ "usb2", IMX_SC_R_USB_2, 1, false, 0 },
|
||||
{ "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 },
|
||||
{ "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 },
|
||||
{ "enet", IMX_SC_R_ENET_0, 2, true, 0 },
|
||||
{ "nand", IMX_SC_R_NAND, 1, false, 0 },
|
||||
{ "mlb", IMX_SC_R_MLB_0, 1, true, 0 },
|
||||
|
||||
/* Audio DMA SS */
|
||||
{ "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 },
|
||||
{ "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 },
|
||||
{ "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 },
|
||||
{ "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 },
|
||||
{ "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 },
|
||||
{ "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 },
|
||||
{ "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 },
|
||||
{ "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 },
|
||||
{ "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 },
|
||||
{ "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 },
|
||||
{ "adma-sai", IMX_SC_R_SAI_0, 3, 1 },
|
||||
{ "adma-amix", IMX_SC_R_AMIX, 1, 0 },
|
||||
{ "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 },
|
||||
{ "adma-dsp", IMX_SC_R_DSP, 1, 0 },
|
||||
{ "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 },
|
||||
{ "adma-can", IMX_SC_R_CAN_0, 3, 1 },
|
||||
{ "adma-ftm", IMX_SC_R_FTM_0, 2, 1 },
|
||||
{ "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 },
|
||||
{ "adma-adc", IMX_SC_R_ADC_0, 1, 1 },
|
||||
{ "adma-lcd", IMX_SC_R_LCD_0, 1, 1 },
|
||||
{ "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 },
|
||||
{ "adma-lpuart", IMX_SC_R_UART_0, 4, 1 },
|
||||
{ "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 },
|
||||
/* AUDIO SS */
|
||||
{ "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 },
|
||||
{ "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 },
|
||||
{ "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 },
|
||||
{ "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 },
|
||||
{ "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 },
|
||||
{ "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
|
||||
{ "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 },
|
||||
{ "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 },
|
||||
{ "esai0", IMX_SC_R_ESAI_0, 1, false, 0 },
|
||||
{ "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 },
|
||||
{ "sai", IMX_SC_R_SAI_0, 3, true, 0 },
|
||||
{ "amix", IMX_SC_R_AMIX, 1, false, 0 },
|
||||
{ "mqs0", IMX_SC_R_MQS_0, 1, false, 0 },
|
||||
{ "dsp", IMX_SC_R_DSP, 1, false, 0 },
|
||||
{ "dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 },
|
||||
|
||||
/* VPU SS */
|
||||
{ "vpu", IMX_SC_R_VPU, 1, 0 },
|
||||
{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 },
|
||||
{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 },
|
||||
{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 },
|
||||
/* DMA SS */
|
||||
{ "can", IMX_SC_R_CAN_0, 3, true, 0 },
|
||||
{ "ftm", IMX_SC_R_FTM_0, 2, true, 0 },
|
||||
{ "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 },
|
||||
{ "adc", IMX_SC_R_ADC_0, 1, true, 0 },
|
||||
{ "lcd", IMX_SC_R_LCD_0, 1, true, 0 },
|
||||
{ "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 },
|
||||
{ "lpuart", IMX_SC_R_UART_0, 4, true, 0 },
|
||||
{ "lpspi", IMX_SC_R_SPI_0, 4, true, 0 },
|
||||
|
||||
/* VPU SS */
|
||||
{ "vpu", IMX_SC_R_VPU, 1, false, 0 },
|
||||
{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 },
|
||||
{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 },
|
||||
{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 },
|
||||
|
||||
/* GPU SS */
|
||||
{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 },
|
||||
{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 },
|
||||
|
||||
/* HSIO SS */
|
||||
{ "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 },
|
||||
{ "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 },
|
||||
{ "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 },
|
||||
{ "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 },
|
||||
{ "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 },
|
||||
{ "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 },
|
||||
|
||||
/* MIPI/LVDS SS */
|
||||
{ "mipi0", IMX_SC_R_MIPI_0, 1, 0 },
|
||||
{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 },
|
||||
{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 },
|
||||
{ "lvds0", IMX_SC_R_LVDS_0, 1, 0 },
|
||||
/* MIPI SS */
|
||||
{ "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 },
|
||||
{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 },
|
||||
{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 },
|
||||
|
||||
/* LVDS SS */
|
||||
{ "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
|
||||
|
||||
/* DC SS */
|
||||
{ "dc0", IMX_SC_R_DC_0, 1, 0 },
|
||||
{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 },
|
||||
{ "dc0", IMX_SC_R_DC_0, 1, false, 0 },
|
||||
{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
|
||||
};
|
||||
|
||||
static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
|
||||
|
@ -236,7 +243,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
|
|||
|
||||
if (pd_ranges->postfix)
|
||||
snprintf(sc_pd->name, sizeof(sc_pd->name),
|
||||
"%s%i", pd_ranges->name, idx);
|
||||
"%s%i", pd_ranges->name, pd_ranges->start_from + idx);
|
||||
else
|
||||
snprintf(sc_pd->name, sizeof(sc_pd->name),
|
||||
"%s", pd_ranges->name);
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
|
||||
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
|
||||
obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
|
||||
|
|
|
@ -406,7 +406,6 @@ static int imx_gpc_probe(struct platform_device *pdev)
|
|||
const struct imx_gpc_dt_data *of_id_data = of_id->data;
|
||||
struct device_node *pgc_node;
|
||||
struct regmap *regmap;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
|
@ -417,8 +416,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
|
|||
!pgc_node)
|
||||
return 0;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
|
|
@ -136,8 +136,8 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
|
|||
GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
|
||||
const bool enable_power_control = !on;
|
||||
const bool has_regulator = !IS_ERR(domain->regulator);
|
||||
unsigned long deadline;
|
||||
int i, ret = 0;
|
||||
u32 pxx_req;
|
||||
|
||||
regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
|
||||
domain->bits.map, domain->bits.map);
|
||||
|
@ -169,30 +169,19 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
|
|||
* As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
|
||||
* for PUP_REQ/PDN_REQ bit to be cleared
|
||||
*/
|
||||
deadline = jiffies + msecs_to_jiffies(1);
|
||||
while (true) {
|
||||
u32 pxx_req;
|
||||
|
||||
regmap_read(domain->regmap, offset, &pxx_req);
|
||||
|
||||
if (!(pxx_req & domain->bits.pxx))
|
||||
break;
|
||||
|
||||
if (time_after(jiffies, deadline)) {
|
||||
dev_err(domain->dev, "falied to command PGC\n");
|
||||
ret = -ETIMEDOUT;
|
||||
/*
|
||||
* If we were in a process of enabling a
|
||||
* domain and failed we might as well disable
|
||||
* the regulator we just enabled. And if it
|
||||
* was the opposite situation and we failed to
|
||||
* power down -- keep the regulator on
|
||||
*/
|
||||
on = !on;
|
||||
break;
|
||||
}
|
||||
|
||||
cpu_relax();
|
||||
ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req,
|
||||
!(pxx_req & domain->bits.pxx),
|
||||
0, USEC_PER_MSEC);
|
||||
if (ret) {
|
||||
dev_err(domain->dev, "failed to command PGC\n");
|
||||
/*
|
||||
* If we were in a process of enabling a
|
||||
* domain and failed we might as well disable
|
||||
* the regulator we just enabled. And if it
|
||||
* was the opposite situation and we failed to
|
||||
* power down -- keep the regulator on
|
||||
*/
|
||||
on = !on;
|
||||
}
|
||||
|
||||
if (enable_power_control)
|
||||
|
@ -574,7 +563,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
|
|||
struct device *dev = &pdev->dev;
|
||||
struct device_node *pgc_np, *np;
|
||||
struct regmap *regmap;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
|
@ -584,8 +572,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2019 NXP.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define REV_B1 0x21
|
||||
|
||||
#define IMX8MQ_SW_INFO_B1 0x40
|
||||
#define IMX8MQ_SW_MAGIC_B1 0xff0055aa
|
||||
|
||||
struct imx8_soc_data {
|
||||
char *name;
|
||||
u32 (*soc_revision)(void);
|
||||
};
|
||||
|
||||
static u32 __init imx8mq_soc_revision(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
void __iomem *ocotp_base;
|
||||
u32 magic;
|
||||
u32 rev = 0;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
|
||||
if (!np)
|
||||
goto out;
|
||||
|
||||
ocotp_base = of_iomap(np, 0);
|
||||
WARN_ON(!ocotp_base);
|
||||
|
||||
magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
|
||||
if (magic == IMX8MQ_SW_MAGIC_B1)
|
||||
rev = REV_B1;
|
||||
|
||||
iounmap(ocotp_base);
|
||||
|
||||
out:
|
||||
of_node_put(np);
|
||||
return rev;
|
||||
}
|
||||
|
||||
static const struct imx8_soc_data imx8mq_soc_data = {
|
||||
.name = "i.MX8MQ",
|
||||
.soc_revision = imx8mq_soc_revision,
|
||||
};
|
||||
|
||||
static const struct of_device_id imx8_soc_match[] = {
|
||||
{ .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
|
||||
{ }
|
||||
};
|
||||
|
||||
#define imx8_revision(soc_rev) \
|
||||
soc_rev ? \
|
||||
kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \
|
||||
"unknown"
|
||||
|
||||
static int __init imx8_soc_init(void)
|
||||
{
|
||||
struct soc_device_attribute *soc_dev_attr;
|
||||
struct soc_device *soc_dev;
|
||||
struct device_node *root;
|
||||
const struct of_device_id *id;
|
||||
u32 soc_rev = 0;
|
||||
const struct imx8_soc_data *data;
|
||||
int ret;
|
||||
|
||||
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
||||
if (!soc_dev_attr)
|
||||
return -ENODEV;
|
||||
|
||||
soc_dev_attr->family = "Freescale i.MX";
|
||||
|
||||
root = of_find_node_by_path("/");
|
||||
ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
|
||||
if (ret)
|
||||
goto free_soc;
|
||||
|
||||
id = of_match_node(imx8_soc_match, root);
|
||||
if (!id)
|
||||
goto free_soc;
|
||||
|
||||
of_node_put(root);
|
||||
|
||||
data = id->data;
|
||||
if (data) {
|
||||
soc_dev_attr->soc_id = data->name;
|
||||
if (data->soc_revision)
|
||||
soc_rev = data->soc_revision();
|
||||
}
|
||||
|
||||
soc_dev_attr->revision = imx8_revision(soc_rev);
|
||||
if (!soc_dev_attr->revision)
|
||||
goto free_soc;
|
||||
|
||||
soc_dev = soc_device_register(soc_dev_attr);
|
||||
if (IS_ERR(soc_dev))
|
||||
goto free_rev;
|
||||
|
||||
return 0;
|
||||
|
||||
free_rev:
|
||||
kfree(soc_dev_attr->revision);
|
||||
free_soc:
|
||||
kfree(soc_dev_attr);
|
||||
of_node_put(root);
|
||||
return -ENODEV;
|
||||
}
|
||||
device_initcall(imx8_soc_init);
|
|
@ -15,4 +15,9 @@
|
|||
|
||||
#include <linux/firmware/imx/svc/misc.h>
|
||||
#include <linux/firmware/imx/svc/pm.h>
|
||||
|
||||
int imx_scu_enable_general_irq_channel(struct device *dev);
|
||||
int imx_scu_irq_register_notifier(struct notifier_block *nb);
|
||||
int imx_scu_irq_unregister_notifier(struct notifier_block *nb);
|
||||
int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable);
|
||||
#endif /* _SC_SCI_H */
|
||||
|
|
Loading…
Reference in New Issue