aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/memory
diff options
context:
space:
mode:
authorAneesh V <aneesh@ti.com>2012-08-17 04:35:15 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-09-04 19:14:31 -0400
commite6b42eb6a66c188642aeb447312938c6f6ebee86 (patch)
tree0deb9e5d95c2668041034fdfd701c60123bb78e2 /drivers/memory
parent6f1cbd4a25c58323b57f1374e827c363b44683cb (diff)
memory: emif: add device tree support to emif driver
Device tree support for the EMIF driver. LPDDR2 generic timings extraction from device is managed using couple of helper functions which can be used by other memory controller drivers. Reviewed-by: Benoit Cousson <b-cousson@ti.com> Reviewed-by: Grant Likely <grant.likely@secretlab.ca> Tested-by: Lokesh Vutla <lokeshvutla@ti.com> Signed-off-by: Aneesh V <aneesh@ti.com> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/memory')
-rw-r--r--drivers/memory/Makefile1
-rw-r--r--drivers/memory/emif.c182
-rw-r--r--drivers/memory/of_memory.c153
-rw-r--r--drivers/memory/of_memory.h36
4 files changed, 371 insertions, 1 deletions
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index 42b3ce9d80fc..cd8486b51f74 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -2,6 +2,7 @@
2# Makefile for memory devices 2# Makefile for memory devices
3# 3#
4 4
5obj-$(CONFIG_OF) += of_memory.o
5obj-$(CONFIG_TI_EMIF) += emif.o 6obj-$(CONFIG_TI_EMIF) += emif.o
6obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o 7obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
7obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o 8obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index 33a4396b24cb..1424ae38e53b 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -18,6 +18,7 @@
18#include <linux/platform_device.h> 18#include <linux/platform_device.h>
19#include <linux/interrupt.h> 19#include <linux/interrupt.h>
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/of.h>
21#include <linux/debugfs.h> 22#include <linux/debugfs.h>
22#include <linux/seq_file.h> 23#include <linux/seq_file.h>
23#include <linux/module.h> 24#include <linux/module.h>
@@ -25,6 +26,7 @@
25#include <linux/spinlock.h> 26#include <linux/spinlock.h>
26#include <memory/jedec_ddr.h> 27#include <memory/jedec_ddr.h>
27#include "emif.h" 28#include "emif.h"
29#include "of_memory.h"
28 30
29/** 31/**
30 * struct emif_data - Per device static data for driver's use 32 * struct emif_data - Per device static data for driver's use
@@ -49,6 +51,7 @@
49 * frequency in effect at the moment) 51 * frequency in effect at the moment)
50 * @plat_data: Pointer to saved platform data. 52 * @plat_data: Pointer to saved platform data.
51 * @debugfs_root: dentry to the root folder for EMIF in debugfs 53 * @debugfs_root: dentry to the root folder for EMIF in debugfs
54 * @np_ddr: Pointer to ddr device tree node
52 */ 55 */
53struct emif_data { 56struct emif_data {
54 u8 duplicate; 57 u8 duplicate;
@@ -63,6 +66,7 @@ struct emif_data {
63 struct emif_regs *curr_regs; 66 struct emif_regs *curr_regs;
64 struct emif_platform_data *plat_data; 67 struct emif_platform_data *plat_data;
65 struct dentry *debugfs_root; 68 struct dentry *debugfs_root;
69 struct device_node *np_ddr;
66}; 70};
67 71
68static struct emif_data *emif1; 72static struct emif_data *emif1;
@@ -1148,6 +1152,168 @@ static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs,
1148 return valid; 1152 return valid;
1149} 1153}
1150 1154
1155#if defined(CONFIG_OF)
1156static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
1157 struct emif_data *emif)
1158{
1159 struct emif_custom_configs *cust_cfgs = NULL;
1160 int len;
1161 const int *lpmode, *poll_intvl;
1162
1163 lpmode = of_get_property(np_emif, "low-power-mode", &len);
1164 poll_intvl = of_get_property(np_emif, "temp-alert-poll-interval", &len);
1165
1166 if (lpmode || poll_intvl)
1167 cust_cfgs = devm_kzalloc(emif->dev, sizeof(*cust_cfgs),
1168 GFP_KERNEL);
1169
1170 if (!cust_cfgs)
1171 return;
1172
1173 if (lpmode) {
1174 cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_LPMODE;
1175 cust_cfgs->lpmode = *lpmode;
1176 of_property_read_u32(np_emif,
1177 "low-power-mode-timeout-performance",
1178 &cust_cfgs->lpmode_timeout_performance);
1179 of_property_read_u32(np_emif,
1180 "low-power-mode-timeout-power",
1181 &cust_cfgs->lpmode_timeout_power);
1182 of_property_read_u32(np_emif,
1183 "low-power-mode-freq-threshold",
1184 &cust_cfgs->lpmode_freq_threshold);
1185 }
1186
1187 if (poll_intvl) {
1188 cust_cfgs->mask |=
1189 EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL;
1190 cust_cfgs->temp_alert_poll_interval_ms = *poll_intvl;
1191 }
1192
1193 if (!is_custom_config_valid(cust_cfgs, emif->dev)) {
1194 devm_kfree(emif->dev, cust_cfgs);
1195 return;
1196 }
1197
1198 emif->plat_data->custom_configs = cust_cfgs;
1199}
1200
1201static void __init_or_module of_get_ddr_info(struct device_node *np_emif,
1202 struct device_node *np_ddr,
1203 struct ddr_device_info *dev_info)
1204{
1205 u32 density = 0, io_width = 0;
1206 int len;
1207
1208 if (of_find_property(np_emif, "cs1-used", &len))
1209 dev_info->cs1_used = true;
1210
1211 if (of_find_property(np_emif, "cal-resistor-per-cs", &len))
1212 dev_info->cal_resistors_per_cs = true;
1213
1214 if (of_device_is_compatible(np_ddr , "jedec,lpddr2-s4"))
1215 dev_info->type = DDR_TYPE_LPDDR2_S4;
1216 else if (of_device_is_compatible(np_ddr , "jedec,lpddr2-s2"))
1217 dev_info->type = DDR_TYPE_LPDDR2_S2;
1218
1219 of_property_read_u32(np_ddr, "density", &density);
1220 of_property_read_u32(np_ddr, "io-width", &io_width);
1221
1222 /* Convert from density in Mb to the density encoding in jedc_ddr.h */
1223 if (density & (density - 1))
1224 dev_info->density = 0;
1225 else
1226 dev_info->density = __fls(density) - 5;
1227
1228 /* Convert from io_width in bits to io_width encoding in jedc_ddr.h */
1229 if (io_width & (io_width - 1))
1230 dev_info->io_width = 0;
1231 else
1232 dev_info->io_width = __fls(io_width) - 1;
1233}
1234
1235static struct emif_data * __init_or_module of_get_memory_device_details(
1236 struct device_node *np_emif, struct device *dev)
1237{
1238 struct emif_data *emif = NULL;
1239 struct ddr_device_info *dev_info = NULL;
1240 struct emif_platform_data *pd = NULL;
1241 struct device_node *np_ddr;
1242 int len;
1243
1244 np_ddr = of_parse_phandle(np_emif, "device-handle", 0);
1245 if (!np_ddr)
1246 goto error;
1247 emif = devm_kzalloc(dev, sizeof(struct emif_data), GFP_KERNEL);
1248 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
1249 dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL);
1250
1251 if (!emif || !pd || !dev_info) {
1252 dev_err(dev, "%s: Out of memory!!\n",
1253 __func__);
1254 goto error;
1255 }
1256
1257 emif->plat_data = pd;
1258 pd->device_info = dev_info;
1259 emif->dev = dev;
1260 emif->np_ddr = np_ddr;
1261 emif->temperature_level = SDRAM_TEMP_NOMINAL;
1262
1263 if (of_device_is_compatible(np_emif, "ti,emif-4d"))
1264 emif->plat_data->ip_rev = EMIF_4D;
1265 else if (of_device_is_compatible(np_emif, "ti,emif-4d5"))
1266 emif->plat_data->ip_rev = EMIF_4D5;
1267
1268 of_property_read_u32(np_emif, "phy-type", &pd->phy_type);
1269
1270 if (of_find_property(np_emif, "hw-caps-ll-interface", &len))
1271 pd->hw_caps |= EMIF_HW_CAPS_LL_INTERFACE;
1272
1273 of_get_ddr_info(np_emif, np_ddr, dev_info);
1274 if (!is_dev_data_valid(pd->device_info->type, pd->device_info->density,
1275 pd->device_info->io_width, pd->phy_type, pd->ip_rev,
1276 emif->dev)) {
1277 dev_err(dev, "%s: invalid device data!!\n", __func__);
1278 goto error;
1279 }
1280 /*
1281 * For EMIF instances other than EMIF1 see if the devices connected
1282 * are exactly same as on EMIF1(which is typically the case). If so,
1283 * mark it as a duplicate of EMIF1. This will save some memory and
1284 * computation.
1285 */
1286 if (emif1 && emif1->np_ddr == np_ddr) {
1287 emif->duplicate = true;
1288 goto out;
1289 } else if (emif1) {
1290 dev_warn(emif->dev, "%s: Non-symmetric DDR geometry\n",
1291 __func__);
1292 }
1293
1294 of_get_custom_configs(np_emif, emif);
1295 emif->plat_data->timings = of_get_ddr_timings(np_ddr, emif->dev,
1296 emif->plat_data->device_info->type,
1297 &emif->plat_data->timings_arr_size);
1298
1299 emif->plat_data->min_tck = of_get_min_tck(np_ddr, emif->dev);
1300 goto out;
1301
1302error:
1303 return NULL;
1304out:
1305 return emif;
1306}
1307
1308#else
1309
1310static struct emif_data * __init_or_module of_get_memory_device_details(
1311 struct device_node *np_emif, struct device *dev)
1312{
1313 return NULL;
1314}
1315#endif
1316
1151static struct emif_data *__init_or_module get_device_details( 1317static struct emif_data *__init_or_module get_device_details(
1152 struct platform_device *pdev) 1318 struct platform_device *pdev)
1153{ 1319{
@@ -1267,7 +1433,11 @@ static int __init_or_module emif_probe(struct platform_device *pdev)
1267 struct resource *res; 1433 struct resource *res;
1268 int irq; 1434 int irq;
1269 1435
1270 emif = get_device_details(pdev); 1436 if (pdev->dev.of_node)
1437 emif = of_get_memory_device_details(pdev->dev.of_node, &pdev->dev);
1438 else
1439 emif = get_device_details(pdev);
1440
1271 if (!emif) { 1441 if (!emif) {
1272 pr_err("%s: error getting device data\n", __func__); 1442 pr_err("%s: error getting device data\n", __func__);
1273 goto error; 1443 goto error;
@@ -1644,11 +1814,21 @@ static void __attribute__((unused)) freq_post_notify_handling(void)
1644 spin_unlock_irqrestore(&emif_lock, irq_state); 1814 spin_unlock_irqrestore(&emif_lock, irq_state);
1645} 1815}
1646 1816
1817#if defined(CONFIG_OF)
1818static const struct of_device_id emif_of_match[] = {
1819 { .compatible = "ti,emif-4d" },
1820 { .compatible = "ti,emif-4d5" },
1821 {},
1822};
1823MODULE_DEVICE_TABLE(of, emif_of_match);
1824#endif
1825
1647static struct platform_driver emif_driver = { 1826static struct platform_driver emif_driver = {
1648 .remove = __exit_p(emif_remove), 1827 .remove = __exit_p(emif_remove),
1649 .shutdown = emif_shutdown, 1828 .shutdown = emif_shutdown,
1650 .driver = { 1829 .driver = {
1651 .name = "emif", 1830 .name = "emif",
1831 .of_match_table = of_match_ptr(emif_of_match),
1652 }, 1832 },
1653}; 1833};
1654 1834
diff --git a/drivers/memory/of_memory.c b/drivers/memory/of_memory.c
new file mode 100644
index 000000000000..60074351f17e
--- /dev/null
+++ b/drivers/memory/of_memory.c
@@ -0,0 +1,153 @@
1/*
2 * OpenFirmware helpers for memory drivers
3 *
4 * Copyright (C) 2012 Texas Instruments, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/device.h>
13#include <linux/platform_device.h>
14#include <linux/list.h>
15#include <linux/of.h>
16#include <linux/gfp.h>
17#include <memory/jedec_ddr.h>
18#include <linux/export.h>
19
20/**
21 * of_get_min_tck() - extract min timing values for ddr
22 * @np: pointer to ddr device tree node
23 * @device: device requesting for min timing values
24 *
25 * Populates the lpddr2_min_tck structure by extracting data
26 * from device tree node. Returns a pointer to the populated
27 * structure. If any error in populating the structure, returns
28 * default min timings provided by JEDEC.
29 */
30const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np,
31 struct device *dev)
32{
33 int ret = 0;
34 struct lpddr2_min_tck *min;
35
36 min = devm_kzalloc(dev, sizeof(*min), GFP_KERNEL);
37 if (!min)
38 goto default_min_tck;
39
40 ret |= of_property_read_u32(np, "tRPab-min-tck", &min->tRPab);
41 ret |= of_property_read_u32(np, "tRCD-min-tck", &min->tRCD);
42 ret |= of_property_read_u32(np, "tWR-min-tck", &min->tWR);
43 ret |= of_property_read_u32(np, "tRASmin-min-tck", &min->tRASmin);
44 ret |= of_property_read_u32(np, "tRRD-min-tck", &min->tRRD);
45 ret |= of_property_read_u32(np, "tWTR-min-tck", &min->tWTR);
46 ret |= of_property_read_u32(np, "tXP-min-tck", &min->tXP);
47 ret |= of_property_read_u32(np, "tRTP-min-tck", &min->tRTP);
48 ret |= of_property_read_u32(np, "tCKE-min-tck", &min->tCKE);
49 ret |= of_property_read_u32(np, "tCKESR-min-tck", &min->tCKESR);
50 ret |= of_property_read_u32(np, "tFAW-min-tck", &min->tFAW);
51
52 if (ret) {
53 devm_kfree(dev, min);
54 goto default_min_tck;
55 }
56
57 return min;
58
59default_min_tck:
60 dev_warn(dev, "%s: using default min-tck values\n", __func__);
61 return &lpddr2_jedec_min_tck;
62}
63EXPORT_SYMBOL(of_get_min_tck);
64
65static int of_do_get_timings(struct device_node *np,
66 struct lpddr2_timings *tim)
67{
68 int ret;
69
70 ret = of_property_read_u32(np, "max-freq", &tim->max_freq);
71 ret |= of_property_read_u32(np, "min-freq", &tim->min_freq);
72 ret |= of_property_read_u32(np, "tRPab", &tim->tRPab);
73 ret |= of_property_read_u32(np, "tRCD", &tim->tRCD);
74 ret |= of_property_read_u32(np, "tWR", &tim->tWR);
75 ret |= of_property_read_u32(np, "tRAS-min", &tim->tRAS_min);
76 ret |= of_property_read_u32(np, "tRRD", &tim->tRRD);
77 ret |= of_property_read_u32(np, "tWTR", &tim->tWTR);
78 ret |= of_property_read_u32(np, "tXP", &tim->tXP);
79 ret |= of_property_read_u32(np, "tRTP", &tim->tRTP);
80 ret |= of_property_read_u32(np, "tCKESR", &tim->tCKESR);
81 ret |= of_property_read_u32(np, "tDQSCK-max", &tim->tDQSCK_max);
82 ret |= of_property_read_u32(np, "tFAW", &tim->tFAW);
83 ret |= of_property_read_u32(np, "tZQCS", &tim->tZQCS);
84 ret |= of_property_read_u32(np, "tZQCL", &tim->tZQCL);
85 ret |= of_property_read_u32(np, "tZQinit", &tim->tZQinit);
86 ret |= of_property_read_u32(np, "tRAS-max-ns", &tim->tRAS_max_ns);
87 ret |= of_property_read_u32(np, "tDQSCK-max-derated",
88 &tim->tDQSCK_max_derated);
89
90 return ret;
91}
92
93/**
94 * of_get_ddr_timings() - extracts the ddr timings and updates no of
95 * frequencies available.
96 * @np_ddr: Pointer to ddr device tree node
97 * @dev: Device requesting for ddr timings
98 * @device_type: Type of ddr(LPDDR2 S2/S4)
99 * @nr_frequencies: No of frequencies available for ddr
100 * (updated by this function)
101 *
102 * Populates lpddr2_timings structure by extracting data from device
103 * tree node. Returns pointer to populated structure. If any error
104 * while populating, returns default timings provided by JEDEC.
105 */
106const struct lpddr2_timings *of_get_ddr_timings(struct device_node *np_ddr,
107 struct device *dev, u32 device_type, u32 *nr_frequencies)
108{
109 struct lpddr2_timings *timings = NULL;
110 u32 arr_sz = 0, i = 0;
111 struct device_node *np_tim;
112 char *tim_compat;
113
114 switch (device_type) {
115 case DDR_TYPE_LPDDR2_S2:
116 case DDR_TYPE_LPDDR2_S4:
117 tim_compat = "jedec,lpddr2-timings";
118 break;
119 default:
120 dev_warn(dev, "%s: un-supported memory type\n", __func__);
121 }
122
123 for_each_child_of_node(np_ddr, np_tim)
124 if (of_device_is_compatible(np_tim, tim_compat))
125 arr_sz++;
126
127 if (arr_sz)
128 timings = devm_kzalloc(dev, sizeof(*timings) * arr_sz,
129 GFP_KERNEL);
130
131 if (!timings)
132 goto default_timings;
133
134 for_each_child_of_node(np_ddr, np_tim) {
135 if (of_device_is_compatible(np_tim, tim_compat)) {
136 if (of_do_get_timings(np_tim, &timings[i])) {
137 devm_kfree(dev, timings);
138 goto default_timings;
139 }
140 i++;
141 }
142 }
143
144 *nr_frequencies = arr_sz;
145
146 return timings;
147
148default_timings:
149 dev_warn(dev, "%s: using default timings\n", __func__);
150 *nr_frequencies = ARRAY_SIZE(lpddr2_jedec_timings);
151 return lpddr2_jedec_timings;
152}
153EXPORT_SYMBOL(of_get_ddr_timings);
diff --git a/drivers/memory/of_memory.h b/drivers/memory/of_memory.h
new file mode 100644
index 000000000000..20b496efed65
--- /dev/null
+++ b/drivers/memory/of_memory.h
@@ -0,0 +1,36 @@
1/*
2 * OpenFirmware helpers for memory drivers
3 *
4 * Copyright (C) 2012 Texas Instruments, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#ifndef __LINUX_MEMORY_OF_REG_H
13#define __LINUX_MEMORY_OF_REG_H
14
15#ifdef CONFIG_OF
16extern const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np,
17 struct device *dev);
18extern const struct lpddr2_timings
19 *of_get_ddr_timings(struct device_node *np_ddr, struct device *dev,
20 u32 device_type, u32 *nr_frequencies);
21#else
22static inline const struct lpddr2_min_tck
23 *of_get_min_tck(struct device_node *np, struct device *dev)
24{
25 return NULL;
26}
27
28static inline const struct lpddr2_timings
29 *of_get_ddr_timings(struct device_node *np_ddr, struct device *dev,
30 u32 device_type, u32 *nr_frequencies)
31{
32 return NULL;
33}
34#endif /* CONFIG_OF */
35
36#endif /* __LINUX_MEMORY_OF_REG_ */