]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/memory/emif.c
memory: emif: add basic infrastructure for EMIF driver
[mirror_ubuntu-bionic-kernel.git] / drivers / memory / emif.c
CommitLineData
7ec94453
A
1/*
2 * EMIF driver
3 *
4 * Copyright (C) 2012 Texas Instruments, Inc.
5 *
6 * Aneesh V <aneesh@ti.com>
7 * Santosh Shilimkar <santosh.shilimkar@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#include <linux/kernel.h>
14#include <linux/reboot.h>
15#include <linux/platform_data/emif_plat.h>
16#include <linux/io.h>
17#include <linux/device.h>
18#include <linux/platform_device.h>
19#include <linux/interrupt.h>
20#include <linux/slab.h>
21#include <linux/seq_file.h>
22#include <linux/module.h>
23#include <linux/list.h>
24#include <memory/jedec_ddr.h>
25#include "emif.h"
26
27/**
28 * struct emif_data - Per device static data for driver's use
29 * @duplicate: Whether the DDR devices attached to this EMIF
30 * instance are exactly same as that on EMIF1. In
31 * this case we can save some memory and processing
32 * @temperature_level: Maximum temperature of LPDDR2 devices attached
33 * to this EMIF - read from MR4 register. If there
34 * are two devices attached to this EMIF, this
35 * value is the maximum of the two temperature
36 * levels.
37 * @node: node in the device list
38 * @base: base address of memory-mapped IO registers.
39 * @dev: device pointer.
40 * @plat_data: Pointer to saved platform data.
41 */
42struct emif_data {
43 u8 duplicate;
44 u8 temperature_level;
45 struct list_head node;
46 void __iomem *base;
47 struct device *dev;
48 struct emif_platform_data *plat_data;
49};
50
51static struct emif_data *emif1;
52static LIST_HEAD(device_list);
53
54static void get_default_timings(struct emif_data *emif)
55{
56 struct emif_platform_data *pd = emif->plat_data;
57
58 pd->timings = lpddr2_jedec_timings;
59 pd->timings_arr_size = ARRAY_SIZE(lpddr2_jedec_timings);
60
61 dev_warn(emif->dev, "%s: using default timings\n", __func__);
62}
63
64static int is_dev_data_valid(u32 type, u32 density, u32 io_width, u32 phy_type,
65 u32 ip_rev, struct device *dev)
66{
67 int valid;
68
69 valid = (type == DDR_TYPE_LPDDR2_S4 ||
70 type == DDR_TYPE_LPDDR2_S2)
71 && (density >= DDR_DENSITY_64Mb
72 && density <= DDR_DENSITY_8Gb)
73 && (io_width >= DDR_IO_WIDTH_8
74 && io_width <= DDR_IO_WIDTH_32);
75
76 /* Combinations of EMIF and PHY revisions that we support today */
77 switch (ip_rev) {
78 case EMIF_4D:
79 valid = valid && (phy_type == EMIF_PHY_TYPE_ATTILAPHY);
80 break;
81 case EMIF_4D5:
82 valid = valid && (phy_type == EMIF_PHY_TYPE_INTELLIPHY);
83 break;
84 default:
85 valid = 0;
86 }
87
88 if (!valid)
89 dev_err(dev, "%s: invalid DDR details\n", __func__);
90 return valid;
91}
92
93static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs,
94 struct device *dev)
95{
96 int valid = 1;
97
98 if ((cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE) &&
99 (cust_cfgs->lpmode != EMIF_LP_MODE_DISABLE))
100 valid = cust_cfgs->lpmode_freq_threshold &&
101 cust_cfgs->lpmode_timeout_performance &&
102 cust_cfgs->lpmode_timeout_power;
103
104 if (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL)
105 valid = valid && cust_cfgs->temp_alert_poll_interval_ms;
106
107 if (!valid)
108 dev_warn(dev, "%s: invalid custom configs\n", __func__);
109
110 return valid;
111}
112
113static struct emif_data *__init_or_module get_device_details(
114 struct platform_device *pdev)
115{
116 u32 size;
117 struct emif_data *emif = NULL;
118 struct ddr_device_info *dev_info;
119 struct emif_custom_configs *cust_cfgs;
120 struct emif_platform_data *pd;
121 struct device *dev;
122 void *temp;
123
124 pd = pdev->dev.platform_data;
125 dev = &pdev->dev;
126
127 if (!(pd && pd->device_info && is_dev_data_valid(pd->device_info->type,
128 pd->device_info->density, pd->device_info->io_width,
129 pd->phy_type, pd->ip_rev, dev))) {
130 dev_err(dev, "%s: invalid device data\n", __func__);
131 goto error;
132 }
133
134 emif = devm_kzalloc(dev, sizeof(*emif), GFP_KERNEL);
135 temp = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
136 dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL);
137
138 if (!emif || !pd || !dev_info) {
139 dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__);
140 goto error;
141 }
142
143 memcpy(temp, pd, sizeof(*pd));
144 pd = temp;
145 memcpy(dev_info, pd->device_info, sizeof(*dev_info));
146
147 pd->device_info = dev_info;
148 emif->plat_data = pd;
149 emif->dev = dev;
150 emif->temperature_level = SDRAM_TEMP_NOMINAL;
151
152 /*
153 * For EMIF instances other than EMIF1 see if the devices connected
154 * are exactly same as on EMIF1(which is typically the case). If so,
155 * mark it as a duplicate of EMIF1 and skip copying timings data.
156 * This will save some memory and some computation later.
157 */
158 emif->duplicate = emif1 && (memcmp(dev_info,
159 emif1->plat_data->device_info,
160 sizeof(struct ddr_device_info)) == 0);
161
162 if (emif->duplicate) {
163 pd->timings = NULL;
164 pd->min_tck = NULL;
165 goto out;
166 } else if (emif1) {
167 dev_warn(emif->dev, "%s: Non-symmetric DDR geometry\n",
168 __func__);
169 }
170
171 /*
172 * Copy custom configs - ignore allocation error, if any, as
173 * custom_configs is not very critical
174 */
175 cust_cfgs = pd->custom_configs;
176 if (cust_cfgs && is_custom_config_valid(cust_cfgs, dev)) {
177 temp = devm_kzalloc(dev, sizeof(*cust_cfgs), GFP_KERNEL);
178 if (temp)
179 memcpy(temp, cust_cfgs, sizeof(*cust_cfgs));
180 else
181 dev_warn(dev, "%s:%d: allocation error\n", __func__,
182 __LINE__);
183 pd->custom_configs = temp;
184 }
185
186 /*
187 * Copy timings and min-tck values from platform data. If it is not
188 * available or if memory allocation fails, use JEDEC defaults
189 */
190 size = sizeof(struct lpddr2_timings) * pd->timings_arr_size;
191 if (pd->timings) {
192 temp = devm_kzalloc(dev, size, GFP_KERNEL);
193 if (temp) {
194 memcpy(temp, pd->timings, sizeof(*pd->timings));
195 pd->timings = temp;
196 } else {
197 dev_warn(dev, "%s:%d: allocation error\n", __func__,
198 __LINE__);
199 get_default_timings(emif);
200 }
201 } else {
202 get_default_timings(emif);
203 }
204
205 if (pd->min_tck) {
206 temp = devm_kzalloc(dev, sizeof(*pd->min_tck), GFP_KERNEL);
207 if (temp) {
208 memcpy(temp, pd->min_tck, sizeof(*pd->min_tck));
209 pd->min_tck = temp;
210 } else {
211 dev_warn(dev, "%s:%d: allocation error\n", __func__,
212 __LINE__);
213 pd->min_tck = &lpddr2_jedec_min_tck;
214 }
215 } else {
216 pd->min_tck = &lpddr2_jedec_min_tck;
217 }
218
219out:
220 return emif;
221
222error:
223 return NULL;
224}
225
226static int __init_or_module emif_probe(struct platform_device *pdev)
227{
228 struct emif_data *emif;
229 struct resource *res;
230
231 emif = get_device_details(pdev);
232 if (!emif) {
233 pr_err("%s: error getting device data\n", __func__);
234 goto error;
235 }
236
237 if (!emif1)
238 emif1 = emif;
239
240 list_add(&emif->node, &device_list);
241
242 /* Save pointers to each other in emif and device structures */
243 emif->dev = &pdev->dev;
244 platform_set_drvdata(pdev, emif);
245
246 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
247 if (!res) {
248 dev_err(emif->dev, "%s: error getting memory resource\n",
249 __func__);
250 goto error;
251 }
252
253 emif->base = devm_request_and_ioremap(emif->dev, res);
254 if (!emif->base) {
255 dev_err(emif->dev, "%s: devm_request_and_ioremap() failed\n",
256 __func__);
257 goto error;
258 }
259
260 dev_info(&pdev->dev, "%s: device configured with addr = %p\n",
261 __func__, emif->base);
262
263 return 0;
264error:
265 return -ENODEV;
266}
267
268static struct platform_driver emif_driver = {
269 .driver = {
270 .name = "emif",
271 },
272};
273
274static int __init_or_module emif_register(void)
275{
276 return platform_driver_probe(&emif_driver, emif_probe);
277}
278
279static void __exit emif_unregister(void)
280{
281 platform_driver_unregister(&emif_driver);
282}
283
284module_init(emif_register);
285module_exit(emif_unregister);
286MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
287MODULE_LICENSE("GPL");
288MODULE_ALIAS("platform:emif");
289MODULE_AUTHOR("Texas Instruments Inc");