Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Marvell Orion pinctrl driver based on mvebu pinctrl core
0004  *
0005  * Author: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
0006  *
0007  * The first 16 MPP pins on Orion are easy to handle: they are
0008  * configured through 2 consecutive registers, located at the base
0009  * address of the MPP device.
0010  *
0011  * However the last 4 MPP pins are handled by a register at offset
0012  * 0x50 from the base address, so it is not consecutive with the first
0013  * two registers.
0014  */
0015 
0016 #include <linux/err.h>
0017 #include <linux/init.h>
0018 #include <linux/io.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/clk.h>
0021 #include <linux/of.h>
0022 #include <linux/of_device.h>
0023 #include <linux/pinctrl/pinctrl.h>
0024 
0025 #include "pinctrl-mvebu.h"
0026 
0027 static void __iomem *mpp_base;
0028 static void __iomem *high_mpp_base;
0029 
0030 static int orion_mpp_ctrl_get(struct mvebu_mpp_ctrl_data *data,
0031                   unsigned pid, unsigned long *config)
0032 {
0033     unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
0034 
0035     if (pid < 16) {
0036         unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
0037         *config = (readl(mpp_base + off) >> shift) & MVEBU_MPP_MASK;
0038     }
0039     else {
0040         *config = (readl(high_mpp_base) >> shift) & MVEBU_MPP_MASK;
0041     }
0042 
0043     return 0;
0044 }
0045 
0046 static int orion_mpp_ctrl_set(struct mvebu_mpp_ctrl_data *data,
0047                   unsigned pid, unsigned long config)
0048 {
0049     unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
0050 
0051     if (pid < 16) {
0052         unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
0053         u32 reg = readl(mpp_base + off) & ~(MVEBU_MPP_MASK << shift);
0054         writel(reg | (config << shift), mpp_base + off);
0055     }
0056     else {
0057         u32 reg = readl(high_mpp_base) & ~(MVEBU_MPP_MASK << shift);
0058         writel(reg | (config << shift), high_mpp_base);
0059     }
0060 
0061     return 0;
0062 }
0063 
0064 #define V(f5181, f5182, f5281) \
0065     ((f5181 << 0) | (f5182 << 1) | (f5281 << 2))
0066 
0067 enum orion_variant {
0068     V_5181  = V(1, 0, 0),
0069     V_5182  = V(0, 1, 0),
0070     V_5281  = V(0, 0, 1),
0071     V_ALL   = V(1, 1, 1),
0072 };
0073 
0074 static struct mvebu_mpp_mode orion_mpp_modes[] = {
0075     MPP_MODE(0,
0076          MPP_VAR_FUNCTION(0x0, "pcie", "rstout",    V_ALL),
0077          MPP_VAR_FUNCTION(0x2, "pci", "req2",       V_ALL),
0078          MPP_VAR_FUNCTION(0x3, "gpio", NULL,        V_ALL)),
0079     MPP_MODE(1,
0080          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0081          MPP_VAR_FUNCTION(0x2, "pci", "gnt2",       V_ALL)),
0082     MPP_MODE(2,
0083          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0084          MPP_VAR_FUNCTION(0x2, "pci", "req3",       V_ALL),
0085          MPP_VAR_FUNCTION(0x3, "pci-1", "pme",      V_ALL)),
0086     MPP_MODE(3,
0087          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0088          MPP_VAR_FUNCTION(0x2, "pci", "gnt3",       V_ALL)),
0089     MPP_MODE(4,
0090          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0091          MPP_VAR_FUNCTION(0x2, "pci", "req4",       V_ALL),
0092          MPP_VAR_FUNCTION(0x4, "bootnand", "re",    V_5182 | V_5281),
0093          MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",    V_5182)),
0094     MPP_MODE(5,
0095          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0096          MPP_VAR_FUNCTION(0x2, "pci", "gnt4",       V_ALL),
0097          MPP_VAR_FUNCTION(0x4, "bootnand", "we",    V_5182 | V_5281),
0098          MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",    V_5182)),
0099     MPP_MODE(6,
0100          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0101          MPP_VAR_FUNCTION(0x2, "pci", "req5",       V_ALL),
0102          MPP_VAR_FUNCTION(0x4, "nand", "re0",       V_5182 | V_5281),
0103          MPP_VAR_FUNCTION(0x5, "pci-1", "clk",      V_5181),
0104          MPP_VAR_FUNCTION(0x5, "sata0", "act",      V_5182)),
0105     MPP_MODE(7,
0106          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0107          MPP_VAR_FUNCTION(0x2, "pci", "gnt5",       V_ALL),
0108          MPP_VAR_FUNCTION(0x4, "nand", "we0",       V_5182 | V_5281),
0109          MPP_VAR_FUNCTION(0x5, "pci-1", "clk",      V_5181),
0110          MPP_VAR_FUNCTION(0x5, "sata1", "act",      V_5182)),
0111     MPP_MODE(8,
0112          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0113          MPP_VAR_FUNCTION(0x1, "ge", "col",         V_ALL)),
0114     MPP_MODE(9,
0115          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0116          MPP_VAR_FUNCTION(0x1, "ge", "rxerr",       V_ALL)),
0117     MPP_MODE(10,
0118          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0119          MPP_VAR_FUNCTION(0x1, "ge", "crs",         V_ALL)),
0120     MPP_MODE(11,
0121          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0122          MPP_VAR_FUNCTION(0x1, "ge", "txerr",       V_ALL)),
0123     MPP_MODE(12,
0124          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0125          MPP_VAR_FUNCTION(0x1, "ge", "txd4",        V_ALL),
0126          MPP_VAR_FUNCTION(0x4, "nand", "re1",       V_5182 | V_5281),
0127          MPP_VAR_FUNCTION(0x5, "sata0", "ledprsnt", V_5182)),
0128     MPP_MODE(13,
0129          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0130          MPP_VAR_FUNCTION(0x1, "ge", "txd5",        V_ALL),
0131          MPP_VAR_FUNCTION(0x4, "nand", "we1",       V_5182 | V_5281),
0132          MPP_VAR_FUNCTION(0x5, "sata1", "ledprsnt", V_5182)),
0133     MPP_MODE(14,
0134          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0135          MPP_VAR_FUNCTION(0x1, "ge", "txd6",        V_ALL),
0136          MPP_VAR_FUNCTION(0x4, "nand", "re2",       V_5182 | V_5281),
0137          MPP_VAR_FUNCTION(0x5, "sata0", "ledact",   V_5182)),
0138     MPP_MODE(15,
0139          MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
0140          MPP_VAR_FUNCTION(0x1, "ge", "txd7",        V_ALL),
0141          MPP_VAR_FUNCTION(0x4, "nand", "we2",       V_5182 | V_5281),
0142          MPP_VAR_FUNCTION(0x5, "sata1", "ledact",   V_5182)),
0143     MPP_MODE(16,
0144          MPP_VAR_FUNCTION(0x0, "uart1", "rxd",      V_5182 | V_5281),
0145          MPP_VAR_FUNCTION(0x1, "ge", "rxd4",        V_ALL),
0146          MPP_VAR_FUNCTION(0x5, "gpio", NULL,        V_5182)),
0147     MPP_MODE(17,
0148          MPP_VAR_FUNCTION(0x0, "uart1", "txd",      V_5182 | V_5281),
0149          MPP_VAR_FUNCTION(0x1, "ge", "rxd5",        V_ALL),
0150          MPP_VAR_FUNCTION(0x5, "gpio", NULL,        V_5182)),
0151     MPP_MODE(18,
0152          MPP_VAR_FUNCTION(0x0, "uart1", "cts",      V_5182 | V_5281),
0153          MPP_VAR_FUNCTION(0x1, "ge", "rxd6",        V_ALL),
0154          MPP_VAR_FUNCTION(0x5, "gpio", NULL,        V_5182)),
0155     MPP_MODE(19,
0156          MPP_VAR_FUNCTION(0x0, "uart1", "rts",      V_5182 | V_5281),
0157          MPP_VAR_FUNCTION(0x1, "ge", "rxd7",        V_ALL),
0158          MPP_VAR_FUNCTION(0x5, "gpio", NULL,        V_5182)),
0159 };
0160 
0161 static const struct mvebu_mpp_ctrl orion_mpp_controls[] = {
0162     MPP_FUNC_CTRL(0, 19, NULL, orion_mpp_ctrl),
0163 };
0164 
0165 static struct pinctrl_gpio_range mv88f5181_gpio_ranges[] = {
0166     MPP_GPIO_RANGE(0, 0, 0, 16),
0167 };
0168 
0169 static struct pinctrl_gpio_range mv88f5182_gpio_ranges[] = {
0170     MPP_GPIO_RANGE(0, 0, 0, 19),
0171 };
0172 
0173 static struct pinctrl_gpio_range mv88f5281_gpio_ranges[] = {
0174     MPP_GPIO_RANGE(0, 0, 0, 16),
0175 };
0176 
0177 static struct mvebu_pinctrl_soc_info mv88f5181_info = {
0178     .variant = V_5181,
0179     .controls = orion_mpp_controls,
0180     .ncontrols = ARRAY_SIZE(orion_mpp_controls),
0181     .modes = orion_mpp_modes,
0182     .nmodes = ARRAY_SIZE(orion_mpp_modes),
0183     .gpioranges = mv88f5181_gpio_ranges,
0184     .ngpioranges = ARRAY_SIZE(mv88f5181_gpio_ranges),
0185 };
0186 
0187 static struct mvebu_pinctrl_soc_info mv88f5182_info = {
0188     .variant = V_5182,
0189     .controls = orion_mpp_controls,
0190     .ncontrols = ARRAY_SIZE(orion_mpp_controls),
0191     .modes = orion_mpp_modes,
0192     .nmodes = ARRAY_SIZE(orion_mpp_modes),
0193     .gpioranges = mv88f5182_gpio_ranges,
0194     .ngpioranges = ARRAY_SIZE(mv88f5182_gpio_ranges),
0195 };
0196 
0197 static struct mvebu_pinctrl_soc_info mv88f5281_info = {
0198     .variant = V_5281,
0199     .controls = orion_mpp_controls,
0200     .ncontrols = ARRAY_SIZE(orion_mpp_controls),
0201     .modes = orion_mpp_modes,
0202     .nmodes = ARRAY_SIZE(orion_mpp_modes),
0203     .gpioranges = mv88f5281_gpio_ranges,
0204     .ngpioranges = ARRAY_SIZE(mv88f5281_gpio_ranges),
0205 };
0206 
0207 /*
0208  * There are multiple variants of the Orion SoCs, but in terms of pin
0209  * muxing, they are identical.
0210  */
0211 static const struct of_device_id orion_pinctrl_of_match[] = {
0212     { .compatible = "marvell,88f5181-pinctrl", .data = &mv88f5181_info },
0213     { .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181_info },
0214     { .compatible = "marvell,88f5182-pinctrl", .data = &mv88f5182_info },
0215     { .compatible = "marvell,88f5281-pinctrl", .data = &mv88f5281_info },
0216     { }
0217 };
0218 
0219 static int orion_pinctrl_probe(struct platform_device *pdev)
0220 {
0221     const struct of_device_id *match =
0222         of_match_device(orion_pinctrl_of_match, &pdev->dev);
0223 
0224     pdev->dev.platform_data = (void*)match->data;
0225 
0226     mpp_base = devm_platform_ioremap_resource(pdev, 0);
0227     if (IS_ERR(mpp_base))
0228         return PTR_ERR(mpp_base);
0229 
0230     high_mpp_base = devm_platform_ioremap_resource(pdev, 1);
0231     if (IS_ERR(high_mpp_base))
0232         return PTR_ERR(high_mpp_base);
0233 
0234     return mvebu_pinctrl_probe(pdev);
0235 }
0236 
0237 static struct platform_driver orion_pinctrl_driver = {
0238     .driver = {
0239         .name = "orion-pinctrl",
0240         .of_match_table = of_match_ptr(orion_pinctrl_of_match),
0241     },
0242     .probe = orion_pinctrl_probe,
0243 };
0244 builtin_platform_driver(orion_pinctrl_driver);