1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * DaVinci / Keystone2 : AEMIF's chip select configuration
4  *
5  */
6 #include <asm/io.h>
7 #include <clk.h>
8 #include <div64.h>
9 #include <dm.h>
10 #include "ti-aemif-cs.h"
11 
12 #define AEMIF_CONFIG(cs)		(0x10 + ((cs) * 4))
13 
14 #define AEMIF_CFG_SELECT_STROBE(v)	((v) ? 1 << 31 : 0)
15 #define AEMIF_CFG_EXTEND_WAIT(v)	((v) ? 1 << 30 : 0)
16 #define AEMIF_CFG_WR_SETUP(v)		(((v) & 0x0f) << 26)
17 #define AEMIF_CFG_WR_STROBE(v)		(((v) & 0x3f) << 20)
18 #define AEMIF_CFG_WR_HOLD(v)		(((v) & 0x07) << 17)
19 #define AEMIF_CFG_RD_SETUP(v)		(((v) & 0x0f) << 13)
20 #define AEMIF_CFG_RD_STROBE(v)		(((v) & 0x3f) << 7)
21 #define AEMIF_CFG_RD_HOLD(v)		(((v) & 0x07) << 4)
22 #define AEMIF_CFG_TURN_AROUND(v)	(((v) & 0x03) << 2)
23 #define AEMIF_CFG_WIDTH(v)		(((v) & 0x03) << 0)
24 
25 #define SSTROBE_EN			0x1
26 #define EW_EN				0x1
27 
28 #define WSETUP_MAX			0xf
29 #define WSTROBE_MAX			0x3f
30 #define WHOLD_MAX			0x7
31 #define RSETUP_MAX			0xf
32 #define RSTROBE_MAX			0x3f
33 #define RHOLD_MAX			0x7
34 #define TA_MAX				0x3
35 
36 #define WIDTH_8BITS			0x0
37 #define WIDTH_16BITS			0x1
38 
39 #define set_config_field(reg, field, val)				\
40 	do {								\
41 		if ((val) != -1) {					\
42 			(reg) &= ~AEMIF_CFG_##field(0xffffffff);	\
43 			(reg) |=	AEMIF_CFG_##field((val));	\
44 		}							\
45 	} while (0)
46 
aemif_cs_configure(int cs,struct aemif_config * cfg)47 void aemif_cs_configure(int cs, struct aemif_config *cfg)
48 {
49 	unsigned long tmp;
50 
51 	tmp = __raw_readl(cfg->base + AEMIF_CONFIG(cs));
52 
53 	set_config_field(tmp, SELECT_STROBE,	cfg->select_strobe);
54 	set_config_field(tmp, EXTEND_WAIT,	cfg->extend_wait);
55 	set_config_field(tmp, WR_SETUP,		cfg->wr_setup);
56 	set_config_field(tmp, WR_STROBE,	cfg->wr_strobe);
57 	set_config_field(tmp, WR_HOLD,		cfg->wr_hold);
58 	set_config_field(tmp, RD_SETUP,		cfg->rd_setup);
59 	set_config_field(tmp, RD_STROBE,	cfg->rd_strobe);
60 	set_config_field(tmp, RD_HOLD,		cfg->rd_hold);
61 	set_config_field(tmp, TURN_AROUND,	cfg->turn_around);
62 	set_config_field(tmp, WIDTH,		cfg->width);
63 
64 	__raw_writel(tmp, cfg->base + AEMIF_CONFIG(cs));
65 }
66 
67 struct ti_aemif_cs {
68 	void __iomem *base;
69 	struct clk *clk;
70 };
71 
aemif_calc_cfg(ulong rate,u64 timing_ns,u32 max_cfg)72 static unsigned int aemif_calc_cfg(ulong rate, u64 timing_ns, u32 max_cfg)
73 {
74 	u64 result;
75 
76 	if (!timing_ns)
77 		return 0;
78 
79 	result = DIV_ROUND_UP_ULL(timing_ns * rate, 1000000000ULL);
80 
81 	if (result - 1 > max_cfg)
82 		return max_cfg;
83 
84 	return result - 1;
85 }
86 
aemif_cs_set_timings(struct udevice * dev)87 static int aemif_cs_set_timings(struct udevice *dev)
88 {
89 	struct ti_aemif_cs *priv = dev_get_priv(dev);
90 	ulong rate = clk_get_rate(priv->clk);
91 	struct aemif_config cfg = {};
92 	u32 val;
93 	u32 cs;
94 
95 	if (dev_read_u32(dev, "ti,cs-chipselect", &cs))
96 		return -EINVAL;
97 
98 /*
99  * On DaVinci SoCs, chipselect is in range [2-5]
100  * On Keystone SoCs, chipselect is in range [0-3]
101  * The logic to access the configuration registers expects the CS to be in the
102  * Keystone range so a -2 offset is applied on DaVinci SoCs
103  */
104 	if (IS_ENABLED(CONFIG_ARCH_DAVINCI)) {
105 		if (cs < 2 || cs > 5)
106 			return -EINVAL;
107 		cs -= 2;
108 	} else if (IS_ENABLED(CONFIG_ARCH_KEYSTONE)) {
109 		if (cs > 3)
110 			return -EINVAL;
111 	}
112 
113 	if (dev_read_bool(dev, "ti,cs-select-strobe-mode"))
114 		cfg.select_strobe = SSTROBE_EN;
115 
116 	if (dev_read_bool(dev, "ti,cs-extended-wait-mode"))
117 		cfg.extend_wait = EW_EN;
118 
119 	val = dev_read_u32_default(dev, "ti,cs-write-setup-ns", U32_MAX);
120 	cfg.wr_setup = aemif_calc_cfg(rate, val, WSETUP_MAX);
121 
122 	val = dev_read_u32_default(dev, "ti,cs-write-strobe-ns", U32_MAX);
123 	cfg.wr_strobe = aemif_calc_cfg(rate, val, WSTROBE_MAX);
124 
125 	val = dev_read_u32_default(dev, "ti,cs-write-hold-ns", U32_MAX);
126 	cfg.wr_hold = aemif_calc_cfg(rate, val, WHOLD_MAX);
127 
128 	val = dev_read_u32_default(dev, "ti,cs-read-setup-ns", U32_MAX);
129 	cfg.rd_setup = aemif_calc_cfg(rate, val, RSETUP_MAX);
130 
131 	val = dev_read_u32_default(dev, "ti,cs-read-strobe-ns", U32_MAX);
132 	cfg.rd_strobe = aemif_calc_cfg(rate, val, RSTROBE_MAX);
133 
134 	val = dev_read_u32_default(dev, "ti,cs-read-hold-ns", U32_MAX);
135 	cfg.rd_hold = aemif_calc_cfg(rate, val, RHOLD_MAX);
136 
137 	val = dev_read_u32_default(dev, "ti,cs-min-turnaround-ns", U32_MAX);
138 	cfg.turn_around = aemif_calc_cfg(rate, val, TA_MAX);
139 
140 	val = dev_read_u32_default(dev, "ti,cs-bus-width", 8);
141 	if (val == 16)
142 		cfg.width = WIDTH_16BITS;
143 	else
144 		cfg.width = WIDTH_8BITS;
145 
146 	cfg.base = priv->base;
147 	aemif_cs_configure(cs, &cfg);
148 
149 	return 0;
150 }
151 
aemif_cs_probe(struct udevice * dev)152 static int aemif_cs_probe(struct udevice *dev)
153 {
154 	struct ti_aemif_cs *priv = dev_get_priv(dev);
155 	struct udevice *aemif;
156 
157 	aemif = dev_get_parent(dev);
158 	if (!aemif)
159 		return -ENODEV;
160 
161 	priv->base = dev_read_addr_ptr(aemif);
162 	if (!priv->base)
163 		return -EINVAL;
164 
165 	priv->clk = devm_clk_get(aemif, "aemif");
166 	if (IS_ERR(priv->clk))
167 		return -EINVAL;
168 
169 	return aemif_cs_set_timings(dev);
170 }
171 
172 static const struct udevice_id aemif_cs_ids[] = {
173 	{ .compatible = "ti,da850-aemif-cs", },
174 	{},
175 };
176 
177 U_BOOT_DRIVER(ti_aemif_cs) = {
178 	.name = "ti_aemif_cs",
179 	.id = UCLASS_MEMORY,
180 	.of_match = aemif_cs_ids,
181 	.probe = aemif_cs_probe,
182 	.priv_auto = sizeof(struct ti_aemif_cs),
183 };
184