1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Driver for NVIDIA Generic Memory Interface |
4 | * |
5 | * Copyright (C) 2016 Host Mobility AB. All rights reserved. |
6 | */ |
7 | |
8 | #include <linux/clk.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/io.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of.h> |
13 | #include <linux/of_platform.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/pm_runtime.h> |
16 | #include <linux/reset.h> |
17 | |
18 | #include <soc/tegra/common.h> |
19 | |
20 | #define TEGRA_GMI_CONFIG 0x00 |
21 | #define TEGRA_GMI_CONFIG_GO BIT(31) |
22 | #define TEGRA_GMI_BUS_WIDTH_32BIT BIT(30) |
23 | #define TEGRA_GMI_MUX_MODE BIT(28) |
24 | #define TEGRA_GMI_RDY_BEFORE_DATA BIT(24) |
25 | #define TEGRA_GMI_RDY_ACTIVE_HIGH BIT(23) |
26 | #define TEGRA_GMI_ADV_ACTIVE_HIGH BIT(22) |
27 | #define TEGRA_GMI_OE_ACTIVE_HIGH BIT(21) |
28 | #define TEGRA_GMI_CS_ACTIVE_HIGH BIT(20) |
29 | #define TEGRA_GMI_CS_SELECT(x) ((x & 0x7) << 4) |
30 | |
31 | #define TEGRA_GMI_TIMING0 0x10 |
32 | #define TEGRA_GMI_MUXED_WIDTH(x) ((x & 0xf) << 12) |
33 | #define TEGRA_GMI_HOLD_WIDTH(x) ((x & 0xf) << 8) |
34 | #define TEGRA_GMI_ADV_WIDTH(x) ((x & 0xf) << 4) |
35 | #define TEGRA_GMI_CE_WIDTH(x) (x & 0xf) |
36 | |
37 | #define TEGRA_GMI_TIMING1 0x14 |
38 | #define TEGRA_GMI_WE_WIDTH(x) ((x & 0xff) << 16) |
39 | #define TEGRA_GMI_OE_WIDTH(x) ((x & 0xff) << 8) |
40 | #define TEGRA_GMI_WAIT_WIDTH(x) (x & 0xff) |
41 | |
42 | #define TEGRA_GMI_MAX_CHIP_SELECT 8 |
43 | |
44 | struct tegra_gmi { |
45 | struct device *dev; |
46 | void __iomem *base; |
47 | struct clk *clk; |
48 | struct reset_control *rst; |
49 | |
50 | u32 snor_config; |
51 | u32 snor_timing0; |
52 | u32 snor_timing1; |
53 | }; |
54 | |
55 | static int tegra_gmi_enable(struct tegra_gmi *gmi) |
56 | { |
57 | int err; |
58 | |
59 | pm_runtime_enable(dev: gmi->dev); |
60 | err = pm_runtime_resume_and_get(dev: gmi->dev); |
61 | if (err) { |
62 | pm_runtime_disable(dev: gmi->dev); |
63 | return err; |
64 | } |
65 | |
66 | reset_control_assert(rstc: gmi->rst); |
67 | usleep_range(min: 2000, max: 4000); |
68 | reset_control_deassert(rstc: gmi->rst); |
69 | |
70 | writel(val: gmi->snor_timing0, addr: gmi->base + TEGRA_GMI_TIMING0); |
71 | writel(val: gmi->snor_timing1, addr: gmi->base + TEGRA_GMI_TIMING1); |
72 | |
73 | gmi->snor_config |= TEGRA_GMI_CONFIG_GO; |
74 | writel(val: gmi->snor_config, addr: gmi->base + TEGRA_GMI_CONFIG); |
75 | |
76 | return 0; |
77 | } |
78 | |
79 | static void tegra_gmi_disable(struct tegra_gmi *gmi) |
80 | { |
81 | u32 config; |
82 | |
83 | /* stop GMI operation */ |
84 | config = readl(addr: gmi->base + TEGRA_GMI_CONFIG); |
85 | config &= ~TEGRA_GMI_CONFIG_GO; |
86 | writel(val: config, addr: gmi->base + TEGRA_GMI_CONFIG); |
87 | |
88 | reset_control_assert(rstc: gmi->rst); |
89 | |
90 | pm_runtime_put_sync_suspend(dev: gmi->dev); |
91 | pm_runtime_force_suspend(dev: gmi->dev); |
92 | } |
93 | |
94 | static int tegra_gmi_parse_dt(struct tegra_gmi *gmi) |
95 | { |
96 | struct device_node *child; |
97 | u32 property, ranges[4]; |
98 | int err; |
99 | |
100 | child = of_get_next_available_child(node: gmi->dev->of_node, NULL); |
101 | if (!child) { |
102 | dev_err(gmi->dev, "no child nodes found\n" ); |
103 | return -ENODEV; |
104 | } |
105 | |
106 | /* |
107 | * We currently only support one child device due to lack of |
108 | * chip-select address decoding. Which means that we only have one |
109 | * chip-select line from the GMI controller. |
110 | */ |
111 | if (of_get_child_count(np: gmi->dev->of_node) > 1) |
112 | dev_warn(gmi->dev, "only one child device is supported." ); |
113 | |
114 | if (of_property_read_bool(np: child, propname: "nvidia,snor-data-width-32bit" )) |
115 | gmi->snor_config |= TEGRA_GMI_BUS_WIDTH_32BIT; |
116 | |
117 | if (of_property_read_bool(np: child, propname: "nvidia,snor-mux-mode" )) |
118 | gmi->snor_config |= TEGRA_GMI_MUX_MODE; |
119 | |
120 | if (of_property_read_bool(np: child, propname: "nvidia,snor-rdy-active-before-data" )) |
121 | gmi->snor_config |= TEGRA_GMI_RDY_BEFORE_DATA; |
122 | |
123 | if (of_property_read_bool(np: child, propname: "nvidia,snor-rdy-active-high" )) |
124 | gmi->snor_config |= TEGRA_GMI_RDY_ACTIVE_HIGH; |
125 | |
126 | if (of_property_read_bool(np: child, propname: "nvidia,snor-adv-active-high" )) |
127 | gmi->snor_config |= TEGRA_GMI_ADV_ACTIVE_HIGH; |
128 | |
129 | if (of_property_read_bool(np: child, propname: "nvidia,snor-oe-active-high" )) |
130 | gmi->snor_config |= TEGRA_GMI_OE_ACTIVE_HIGH; |
131 | |
132 | if (of_property_read_bool(np: child, propname: "nvidia,snor-cs-active-high" )) |
133 | gmi->snor_config |= TEGRA_GMI_CS_ACTIVE_HIGH; |
134 | |
135 | /* Decode the CS# */ |
136 | err = of_property_read_u32_array(np: child, propname: "ranges" , out_values: ranges, sz: 4); |
137 | if (err < 0) { |
138 | /* Invalid binding */ |
139 | if (err == -EOVERFLOW) { |
140 | dev_err(gmi->dev, |
141 | "failed to decode CS: invalid ranges length\n" ); |
142 | goto error_cs; |
143 | } |
144 | |
145 | /* |
146 | * If we reach here it means that the child node has an empty |
147 | * ranges or it does not exist at all. Attempt to decode the |
148 | * CS# from the reg property instead. |
149 | */ |
150 | err = of_property_read_u32(np: child, propname: "reg" , out_value: &property); |
151 | if (err < 0) { |
152 | dev_err(gmi->dev, |
153 | "failed to decode CS: no reg property found\n" ); |
154 | goto error_cs; |
155 | } |
156 | } else { |
157 | property = ranges[1]; |
158 | } |
159 | |
160 | /* Valid chip selects are CS0-CS7 */ |
161 | if (property >= TEGRA_GMI_MAX_CHIP_SELECT) { |
162 | dev_err(gmi->dev, "invalid chip select: %d" , property); |
163 | err = -EINVAL; |
164 | goto error_cs; |
165 | } |
166 | |
167 | gmi->snor_config |= TEGRA_GMI_CS_SELECT(property); |
168 | |
169 | /* The default values that are provided below are reset values */ |
170 | if (!of_property_read_u32(np: child, propname: "nvidia,snor-muxed-width" , out_value: &property)) |
171 | gmi->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(property); |
172 | else |
173 | gmi->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(1); |
174 | |
175 | if (!of_property_read_u32(np: child, propname: "nvidia,snor-hold-width" , out_value: &property)) |
176 | gmi->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(property); |
177 | else |
178 | gmi->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(1); |
179 | |
180 | if (!of_property_read_u32(np: child, propname: "nvidia,snor-adv-width" , out_value: &property)) |
181 | gmi->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(property); |
182 | else |
183 | gmi->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(1); |
184 | |
185 | if (!of_property_read_u32(np: child, propname: "nvidia,snor-ce-width" , out_value: &property)) |
186 | gmi->snor_timing0 |= TEGRA_GMI_CE_WIDTH(property); |
187 | else |
188 | gmi->snor_timing0 |= TEGRA_GMI_CE_WIDTH(4); |
189 | |
190 | if (!of_property_read_u32(np: child, propname: "nvidia,snor-we-width" , out_value: &property)) |
191 | gmi->snor_timing1 |= TEGRA_GMI_WE_WIDTH(property); |
192 | else |
193 | gmi->snor_timing1 |= TEGRA_GMI_WE_WIDTH(1); |
194 | |
195 | if (!of_property_read_u32(np: child, propname: "nvidia,snor-oe-width" , out_value: &property)) |
196 | gmi->snor_timing1 |= TEGRA_GMI_OE_WIDTH(property); |
197 | else |
198 | gmi->snor_timing1 |= TEGRA_GMI_OE_WIDTH(1); |
199 | |
200 | if (!of_property_read_u32(np: child, propname: "nvidia,snor-wait-width" , out_value: &property)) |
201 | gmi->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(property); |
202 | else |
203 | gmi->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(3); |
204 | |
205 | error_cs: |
206 | of_node_put(node: child); |
207 | return err; |
208 | } |
209 | |
210 | static int tegra_gmi_probe(struct platform_device *pdev) |
211 | { |
212 | struct device *dev = &pdev->dev; |
213 | struct tegra_gmi *gmi; |
214 | int err; |
215 | |
216 | gmi = devm_kzalloc(dev, size: sizeof(*gmi), GFP_KERNEL); |
217 | if (!gmi) |
218 | return -ENOMEM; |
219 | |
220 | platform_set_drvdata(pdev, data: gmi); |
221 | gmi->dev = dev; |
222 | |
223 | gmi->base = devm_platform_ioremap_resource(pdev, index: 0); |
224 | if (IS_ERR(ptr: gmi->base)) |
225 | return PTR_ERR(ptr: gmi->base); |
226 | |
227 | gmi->clk = devm_clk_get(dev, id: "gmi" ); |
228 | if (IS_ERR(ptr: gmi->clk)) { |
229 | dev_err(dev, "can not get clock\n" ); |
230 | return PTR_ERR(ptr: gmi->clk); |
231 | } |
232 | |
233 | gmi->rst = devm_reset_control_get(dev, id: "gmi" ); |
234 | if (IS_ERR(ptr: gmi->rst)) { |
235 | dev_err(dev, "can not get reset\n" ); |
236 | return PTR_ERR(ptr: gmi->rst); |
237 | } |
238 | |
239 | err = devm_tegra_core_dev_init_opp_table_common(dev: &pdev->dev); |
240 | if (err) |
241 | return err; |
242 | |
243 | err = tegra_gmi_parse_dt(gmi); |
244 | if (err) |
245 | return err; |
246 | |
247 | err = tegra_gmi_enable(gmi); |
248 | if (err < 0) |
249 | return err; |
250 | |
251 | err = of_platform_default_populate(root: dev->of_node, NULL, parent: dev); |
252 | if (err < 0) { |
253 | dev_err(dev, "fail to create devices.\n" ); |
254 | tegra_gmi_disable(gmi); |
255 | return err; |
256 | } |
257 | |
258 | return 0; |
259 | } |
260 | |
261 | static int tegra_gmi_remove(struct platform_device *pdev) |
262 | { |
263 | struct tegra_gmi *gmi = platform_get_drvdata(pdev); |
264 | |
265 | of_platform_depopulate(parent: gmi->dev); |
266 | tegra_gmi_disable(gmi); |
267 | |
268 | return 0; |
269 | } |
270 | |
271 | static int __maybe_unused tegra_gmi_runtime_resume(struct device *dev) |
272 | { |
273 | struct tegra_gmi *gmi = dev_get_drvdata(dev); |
274 | int err; |
275 | |
276 | err = clk_prepare_enable(clk: gmi->clk); |
277 | if (err < 0) { |
278 | dev_err(gmi->dev, "failed to enable clock: %d\n" , err); |
279 | return err; |
280 | } |
281 | |
282 | return 0; |
283 | } |
284 | |
285 | static int __maybe_unused tegra_gmi_runtime_suspend(struct device *dev) |
286 | { |
287 | struct tegra_gmi *gmi = dev_get_drvdata(dev); |
288 | |
289 | clk_disable_unprepare(clk: gmi->clk); |
290 | |
291 | return 0; |
292 | } |
293 | |
294 | static const struct dev_pm_ops tegra_gmi_pm = { |
295 | SET_RUNTIME_PM_OPS(tegra_gmi_runtime_suspend, tegra_gmi_runtime_resume, |
296 | NULL) |
297 | }; |
298 | |
299 | static const struct of_device_id tegra_gmi_id_table[] = { |
300 | { .compatible = "nvidia,tegra20-gmi" , }, |
301 | { .compatible = "nvidia,tegra30-gmi" , }, |
302 | { } |
303 | }; |
304 | MODULE_DEVICE_TABLE(of, tegra_gmi_id_table); |
305 | |
306 | static struct platform_driver tegra_gmi_driver = { |
307 | .probe = tegra_gmi_probe, |
308 | .remove = tegra_gmi_remove, |
309 | .driver = { |
310 | .name = "tegra-gmi" , |
311 | .of_match_table = tegra_gmi_id_table, |
312 | .pm = &tegra_gmi_pm, |
313 | }, |
314 | }; |
315 | module_platform_driver(tegra_gmi_driver); |
316 | |
317 | MODULE_AUTHOR("Mirza Krak <mirza.krak@gmail.com" ); |
318 | MODULE_DESCRIPTION("NVIDIA Tegra GMI Bus Driver" ); |
319 | MODULE_LICENSE("GPL v2" ); |
320 | |