diff options
author | A.s. Dong <aisheng.dong@nxp.com> | 2018-10-30 17:10:51 +0300 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2018-11-05 11:33:32 +0300 |
commit | b96eea718bf697e4a490c2fabfb89995b9193c21 (patch) | |
tree | 29b332e72b22312d8ba9656f1cb55d0dac5cd952 /drivers/pinctrl/freescale/pinctrl-scu.c | |
parent | 1ccb0426d7b6a94434a7b4f8d2d7f57de3c1b653 (diff) | |
download | linux-b96eea718bf697e4a490c2fabfb89995b9193c21.tar.xz |
pinctrl: fsl: add scu based pinctrl support
Some i.MX SoCs (e.g. MX8QXP and MX8QM) contain a system controller
that is responsible for controlling the pad setting of the IPs that
are present. Communication between the host processor running an OS
and the system controller happens through a SCU protocol.
This patch classifies the pad settings into two categories: MMIO and SCU.
For the original MMIO method, no functional changes except organize them
into a few imx_*_mmio() functions. Besides that, we add the SCU based
Pad Mux and Pinconf setting support which are implemented in pinctrl-scu.c.
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Stefan Agner <stefan@agner.ch>
Cc: Pengutronix Kernel Team <kernel@pengutronix.de>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/freescale/pinctrl-scu.c')
-rw-r--r-- | drivers/pinctrl/freescale/pinctrl-scu.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/drivers/pinctrl/freescale/pinctrl-scu.c b/drivers/pinctrl/freescale/pinctrl-scu.c new file mode 100644 index 000000000000..83e69c0f39e6 --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-scu.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + * Dong Aisheng <aisheng.dong@nxp.com> + */ + +#include <linux/err.h> +#include <linux/firmware/imx/sci.h> +#include <linux/of_address.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/platform_device.h> + +#include "../core.h" +#include "pinctrl-imx.h" + +enum pad_func_e { + IMX_SC_PAD_FUNC_SET = 15, + IMX_SC_PAD_FUNC_GET = 16, +}; + +struct imx_sc_msg_req_pad_set { + struct imx_sc_rpc_msg hdr; + u32 val; + u16 pad; +} __packed; + +struct imx_sc_msg_req_pad_get { + struct imx_sc_rpc_msg hdr; + u16 pad; +} __packed; + +struct imx_sc_msg_resp_pad_get { + struct imx_sc_rpc_msg hdr; + u32 val; +} __packed; + +struct imx_sc_ipc *pinctrl_ipc_handle; + +int imx_pinctrl_sc_ipc_init(struct platform_device *pdev) +{ + return imx_scu_get_handle(&pinctrl_ipc_handle); +} + +int imx_pinconf_get_scu(struct pinctrl_dev *pctldev, unsigned pin_id, + unsigned long *config) +{ + struct imx_sc_msg_req_pad_get msg; + struct imx_sc_msg_resp_pad_get *resp; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_PAD; + hdr->func = IMX_SC_PAD_FUNC_GET; + hdr->size = 2; + + msg.pad = pin_id; + + ret = imx_scu_call_rpc(pinctrl_ipc_handle, &msg, true); + if (ret) + return ret; + + resp = (struct imx_sc_msg_resp_pad_get *)&msg; + *config = resp->val; + + return 0; +} + +int imx_pinconf_set_scu(struct pinctrl_dev *pctldev, unsigned pin_id, + unsigned long *configs, unsigned num_configs) +{ + struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); + struct imx_sc_msg_req_pad_set msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + unsigned int mux = configs[0]; + unsigned int conf = configs[1]; + unsigned int val; + int ret; + + /* + * Set mux and conf together in one IPC call + */ + WARN_ON(num_configs != 2); + + val = conf | BM_PAD_CTL_IFMUX_ENABLE | BM_PAD_CTL_GP_ENABLE; + val |= mux << BP_PAD_CTL_IFMUX; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_PAD; + hdr->func = IMX_SC_PAD_FUNC_SET; + hdr->size = 3; + + msg.pad = pin_id; + msg.val = val; + + ret = imx_scu_call_rpc(pinctrl_ipc_handle, &msg, true); + + dev_dbg(ipctl->dev, "write: pin_id %u config 0x%x val 0x%x\n", + pin_id, conf, val); + + return ret; +} + +void imx_pinctrl_parse_pin_scu(struct imx_pinctrl *ipctl, + unsigned int *pin_id, struct imx_pin *pin, + const __be32 **list_p) +{ + const struct imx_pinctrl_soc_info *info = ipctl->info; + struct imx_pin_scu *pin_scu = &pin->conf.scu; + const __be32 *list = *list_p; + + pin->pin = be32_to_cpu(*list++); + *pin_id = pin->pin; + pin_scu->mux_mode = be32_to_cpu(*list++); + pin_scu->config = be32_to_cpu(*list++); + *list_p = list; + + dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[pin->pin].name, + pin_scu->mux_mode, pin_scu->config); +} |