1656e6cc8SKonstantin Porotchkin /*
2656e6cc8SKonstantin Porotchkin * Copyright (C) 2016 Marvell International Ltd.
3656e6cc8SKonstantin Porotchkin *
4656e6cc8SKonstantin Porotchkin * SPDX-License-Identifier: GPL-2.0
5656e6cc8SKonstantin Porotchkin * https://spdx.org/licenses
6656e6cc8SKonstantin Porotchkin */
7656e6cc8SKonstantin Porotchkin
8656e6cc8SKonstantin Porotchkin #include <common.h>
9656e6cc8SKonstantin Porotchkin #include <config.h>
10656e6cc8SKonstantin Porotchkin #include <fdtdec.h>
11656e6cc8SKonstantin Porotchkin #include <errno.h>
12656e6cc8SKonstantin Porotchkin #include <dm.h>
13656e6cc8SKonstantin Porotchkin #include <dm/pinctrl.h>
14656e6cc8SKonstantin Porotchkin #include <dm/root.h>
15656e6cc8SKonstantin Porotchkin #include <asm/system.h>
16656e6cc8SKonstantin Porotchkin #include <asm/io.h>
17656e6cc8SKonstantin Porotchkin #include <asm/arch-armada8k/soc-info.h>
18656e6cc8SKonstantin Porotchkin #include "pinctrl-mvebu.h"
19656e6cc8SKonstantin Porotchkin
20656e6cc8SKonstantin Porotchkin DECLARE_GLOBAL_DATA_PTR;
21656e6cc8SKonstantin Porotchkin
22656e6cc8SKonstantin Porotchkin /*
23656e6cc8SKonstantin Porotchkin * mvebu_pinctrl_set_state: configure pin functions.
24656e6cc8SKonstantin Porotchkin * @dev: the pinctrl device to be configured.
25656e6cc8SKonstantin Porotchkin * @config: the state to be configured.
26656e6cc8SKonstantin Porotchkin * @return: 0 in success
27656e6cc8SKonstantin Porotchkin */
mvebu_pinctrl_set_state(struct udevice * dev,struct udevice * config)28656e6cc8SKonstantin Porotchkin int mvebu_pinctrl_set_state(struct udevice *dev, struct udevice *config)
29656e6cc8SKonstantin Porotchkin {
30656e6cc8SKonstantin Porotchkin const void *blob = gd->fdt_blob;
31e160f7d4SSimon Glass int node = dev_of_offset(config);
32656e6cc8SKonstantin Porotchkin struct mvebu_pinctrl_priv *priv;
33656e6cc8SKonstantin Porotchkin u32 pin_arr[MVEBU_MAX_PINS_PER_BANK];
34656e6cc8SKonstantin Porotchkin u32 function;
35656e6cc8SKonstantin Porotchkin int i, pin_count;
36656e6cc8SKonstantin Porotchkin
37656e6cc8SKonstantin Porotchkin priv = dev_get_priv(dev);
38656e6cc8SKonstantin Porotchkin
39656e6cc8SKonstantin Porotchkin pin_count = fdtdec_get_int_array_count(blob, node,
40656e6cc8SKonstantin Porotchkin "marvell,pins",
41656e6cc8SKonstantin Porotchkin pin_arr,
42656e6cc8SKonstantin Porotchkin MVEBU_MAX_PINS_PER_BANK);
43656e6cc8SKonstantin Porotchkin if (pin_count <= 0) {
44656e6cc8SKonstantin Porotchkin debug("Failed reading pins array for pinconfig %s (%d)\n",
45656e6cc8SKonstantin Porotchkin config->name, pin_count);
46656e6cc8SKonstantin Porotchkin return -EINVAL;
47656e6cc8SKonstantin Porotchkin }
48656e6cc8SKonstantin Porotchkin
49656e6cc8SKonstantin Porotchkin function = fdtdec_get_int(blob, node, "marvell,function", 0xff);
50656e6cc8SKonstantin Porotchkin
51656e6cc8SKonstantin Porotchkin for (i = 0; i < pin_count; i++) {
52656e6cc8SKonstantin Porotchkin int reg_offset;
53656e6cc8SKonstantin Porotchkin int field_offset;
54656e6cc8SKonstantin Porotchkin int pin = pin_arr[i];
55656e6cc8SKonstantin Porotchkin
56656e6cc8SKonstantin Porotchkin if (function > priv->max_func) {
57656e6cc8SKonstantin Porotchkin debug("Illegal function %d for pinconfig %s\n",
58656e6cc8SKonstantin Porotchkin function, config->name);
59656e6cc8SKonstantin Porotchkin return -EINVAL;
60656e6cc8SKonstantin Porotchkin }
61656e6cc8SKonstantin Porotchkin
62656e6cc8SKonstantin Porotchkin /* Calculate register address and bit in register */
63656e6cc8SKonstantin Porotchkin reg_offset = priv->reg_direction * 4 *
64656e6cc8SKonstantin Porotchkin (pin >> (PIN_REG_SHIFT));
65656e6cc8SKonstantin Porotchkin field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
66656e6cc8SKonstantin Porotchkin
67656e6cc8SKonstantin Porotchkin clrsetbits_le32(priv->base_reg + reg_offset,
68656e6cc8SKonstantin Porotchkin PIN_FUNC_MASK << field_offset,
69656e6cc8SKonstantin Porotchkin (function & PIN_FUNC_MASK) << field_offset);
70656e6cc8SKonstantin Porotchkin }
71656e6cc8SKonstantin Porotchkin
72656e6cc8SKonstantin Porotchkin return 0;
73656e6cc8SKonstantin Porotchkin }
74656e6cc8SKonstantin Porotchkin
75656e6cc8SKonstantin Porotchkin /*
76656e6cc8SKonstantin Porotchkin * mvebu_pinctrl_set_state_all: configure the entire bank pin functions.
77656e6cc8SKonstantin Porotchkin * @dev: the pinctrl device to be configured.
78656e6cc8SKonstantin Porotchkin * @config: the state to be configured.
79656e6cc8SKonstantin Porotchkin * @return: 0 in success
80656e6cc8SKonstantin Porotchkin */
mvebu_pinctrl_set_state_all(struct udevice * dev,struct udevice * config)81656e6cc8SKonstantin Porotchkin static int mvebu_pinctrl_set_state_all(struct udevice *dev,
82656e6cc8SKonstantin Porotchkin struct udevice *config)
83656e6cc8SKonstantin Porotchkin {
84656e6cc8SKonstantin Porotchkin const void *blob = gd->fdt_blob;
85e160f7d4SSimon Glass int node = dev_of_offset(config);
86656e6cc8SKonstantin Porotchkin struct mvebu_pinctrl_priv *priv;
87656e6cc8SKonstantin Porotchkin u32 func_arr[MVEBU_MAX_PINS_PER_BANK];
88656e6cc8SKonstantin Porotchkin int pin, err;
89656e6cc8SKonstantin Porotchkin
90656e6cc8SKonstantin Porotchkin priv = dev_get_priv(dev);
91656e6cc8SKonstantin Porotchkin
92656e6cc8SKonstantin Porotchkin err = fdtdec_get_int_array(blob, node, "pin-func",
93656e6cc8SKonstantin Porotchkin func_arr, priv->pin_cnt);
94656e6cc8SKonstantin Porotchkin if (err) {
95656e6cc8SKonstantin Porotchkin debug("Failed reading pin functions for bank %s\n",
96656e6cc8SKonstantin Porotchkin priv->bank_name);
97656e6cc8SKonstantin Porotchkin return -EINVAL;
98656e6cc8SKonstantin Porotchkin }
99656e6cc8SKonstantin Porotchkin
100656e6cc8SKonstantin Porotchkin for (pin = 0; pin < priv->pin_cnt; pin++) {
101656e6cc8SKonstantin Porotchkin int reg_offset;
102656e6cc8SKonstantin Porotchkin int field_offset;
103656e6cc8SKonstantin Porotchkin u32 func = func_arr[pin];
104656e6cc8SKonstantin Porotchkin
105656e6cc8SKonstantin Porotchkin /* Bypass pins with function 0xFF */
106656e6cc8SKonstantin Porotchkin if (func == 0xff) {
107656e6cc8SKonstantin Porotchkin debug("Warning: pin %d value is not modified ", pin);
108656e6cc8SKonstantin Porotchkin debug("(kept as default)\n");
109656e6cc8SKonstantin Porotchkin continue;
110656e6cc8SKonstantin Porotchkin } else if (func > priv->max_func) {
111656e6cc8SKonstantin Porotchkin debug("Illegal function %d for pin %d\n", func, pin);
112656e6cc8SKonstantin Porotchkin return -EINVAL;
113656e6cc8SKonstantin Porotchkin }
114656e6cc8SKonstantin Porotchkin
115656e6cc8SKonstantin Porotchkin /* Calculate register address and bit in register */
116656e6cc8SKonstantin Porotchkin reg_offset = priv->reg_direction * 4 *
117656e6cc8SKonstantin Porotchkin (pin >> (PIN_REG_SHIFT));
118656e6cc8SKonstantin Porotchkin field_offset = (BITS_PER_PIN) * (pin & PIN_FIELD_MASK);
119656e6cc8SKonstantin Porotchkin
120656e6cc8SKonstantin Porotchkin clrsetbits_le32(priv->base_reg + reg_offset,
121656e6cc8SKonstantin Porotchkin PIN_FUNC_MASK << field_offset,
122656e6cc8SKonstantin Porotchkin (func & PIN_FUNC_MASK) << field_offset);
123656e6cc8SKonstantin Porotchkin }
124656e6cc8SKonstantin Porotchkin
125656e6cc8SKonstantin Porotchkin return 0;
126656e6cc8SKonstantin Porotchkin }
127656e6cc8SKonstantin Porotchkin
mvebu_pinctl_probe(struct udevice * dev)128656e6cc8SKonstantin Porotchkin int mvebu_pinctl_probe(struct udevice *dev)
129656e6cc8SKonstantin Porotchkin {
130656e6cc8SKonstantin Porotchkin const void *blob = gd->fdt_blob;
131e160f7d4SSimon Glass int node = dev_of_offset(dev);
132656e6cc8SKonstantin Porotchkin struct mvebu_pinctrl_priv *priv;
133656e6cc8SKonstantin Porotchkin
134656e6cc8SKonstantin Porotchkin priv = dev_get_priv(dev);
135656e6cc8SKonstantin Porotchkin if (!priv) {
136656e6cc8SKonstantin Porotchkin debug("%s: Failed to get private\n", __func__);
137656e6cc8SKonstantin Porotchkin return -EINVAL;
138656e6cc8SKonstantin Porotchkin }
139656e6cc8SKonstantin Porotchkin
140*a821c4afSSimon Glass priv->base_reg = devfdt_get_addr_ptr(dev);
141656e6cc8SKonstantin Porotchkin if (priv->base_reg == (void *)FDT_ADDR_T_NONE) {
142656e6cc8SKonstantin Porotchkin debug("%s: Failed to get base address\n", __func__);
143656e6cc8SKonstantin Porotchkin return -EINVAL;
144656e6cc8SKonstantin Porotchkin }
145656e6cc8SKonstantin Porotchkin
146656e6cc8SKonstantin Porotchkin priv->pin_cnt = fdtdec_get_int(blob, node, "pin-count",
147656e6cc8SKonstantin Porotchkin MVEBU_MAX_PINS_PER_BANK);
148656e6cc8SKonstantin Porotchkin priv->max_func = fdtdec_get_int(blob, node, "max-func",
149656e6cc8SKonstantin Porotchkin MVEBU_MAX_FUNC);
150656e6cc8SKonstantin Porotchkin priv->bank_name = fdt_getprop(blob, node, "bank-name", NULL);
151656e6cc8SKonstantin Porotchkin
152656e6cc8SKonstantin Porotchkin priv->reg_direction = 1;
153656e6cc8SKonstantin Porotchkin if (fdtdec_get_bool(blob, node, "reverse-reg"))
154656e6cc8SKonstantin Porotchkin priv->reg_direction = -1;
155656e6cc8SKonstantin Porotchkin
156656e6cc8SKonstantin Porotchkin return mvebu_pinctrl_set_state_all(dev, dev);
157656e6cc8SKonstantin Porotchkin }
158656e6cc8SKonstantin Porotchkin
159656e6cc8SKonstantin Porotchkin static struct pinctrl_ops mvebu_pinctrl_ops = {
160656e6cc8SKonstantin Porotchkin .set_state = mvebu_pinctrl_set_state
161656e6cc8SKonstantin Porotchkin };
162656e6cc8SKonstantin Porotchkin
163656e6cc8SKonstantin Porotchkin static const struct udevice_id mvebu_pinctrl_ids[] = {
164656e6cc8SKonstantin Porotchkin { .compatible = "marvell,mvebu-pinctrl" },
165656e6cc8SKonstantin Porotchkin { .compatible = "marvell,armada-ap806-pinctrl" },
166656e6cc8SKonstantin Porotchkin { .compatible = "marvell,a70x0-pinctrl" },
167656e6cc8SKonstantin Porotchkin { .compatible = "marvell,a80x0-cp0-pinctrl" },
168656e6cc8SKonstantin Porotchkin { .compatible = "marvell,a80x0-cp1-pinctrl" },
169656e6cc8SKonstantin Porotchkin { }
170656e6cc8SKonstantin Porotchkin };
171656e6cc8SKonstantin Porotchkin
172656e6cc8SKonstantin Porotchkin U_BOOT_DRIVER(pinctrl_mvebu) = {
173656e6cc8SKonstantin Porotchkin .name = "mvebu_pinctrl",
174656e6cc8SKonstantin Porotchkin .id = UCLASS_PINCTRL,
175656e6cc8SKonstantin Porotchkin .of_match = mvebu_pinctrl_ids,
176656e6cc8SKonstantin Porotchkin .priv_auto_alloc_size = sizeof(struct mvebu_pinctrl_priv),
177656e6cc8SKonstantin Porotchkin .ops = &mvebu_pinctrl_ops,
178656e6cc8SKonstantin Porotchkin .probe = mvebu_pinctl_probe
179656e6cc8SKonstantin Porotchkin };
180