Commit e6b42eb6a66c188642aeb447312938c6f6ebee86

Authored by Aneesh V
Committed by Greg Kroah-Hartman
1 parent 6f1cbd4a25

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>

Showing 4 changed files with 371 additions and 1 deletions Side-by-side Diff

drivers/memory/Makefile
... ... @@ -2,6 +2,7 @@
2 2 # Makefile for memory devices
3 3 #
4 4  
  5 +obj-$(CONFIG_OF) += of_memory.o
5 6 obj-$(CONFIG_TI_EMIF) += emif.o
6 7 obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
7 8 obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o
drivers/memory/emif.c
... ... @@ -18,6 +18,7 @@
18 18 #include <linux/platform_device.h>
19 19 #include <linux/interrupt.h>
20 20 #include <linux/slab.h>
  21 +#include <linux/of.h>
21 22 #include <linux/debugfs.h>
22 23 #include <linux/seq_file.h>
23 24 #include <linux/module.h>
... ... @@ -25,6 +26,7 @@
25 26 #include <linux/spinlock.h>
26 27 #include <memory/jedec_ddr.h>
27 28 #include "emif.h"
  29 +#include "of_memory.h"
28 30  
29 31 /**
30 32 * struct emif_data - Per device static data for driver's use
... ... @@ -49,6 +51,7 @@
49 51 * frequency in effect at the moment)
50 52 * @plat_data: Pointer to saved platform data.
51 53 * @debugfs_root: dentry to the root folder for EMIF in debugfs
  54 + * @np_ddr: Pointer to ddr device tree node
52 55 */
53 56 struct emif_data {
54 57 u8 duplicate;
... ... @@ -63,6 +66,7 @@
63 66 struct emif_regs *curr_regs;
64 67 struct emif_platform_data *plat_data;
65 68 struct dentry *debugfs_root;
  69 + struct device_node *np_ddr;
66 70 };
67 71  
68 72 static struct emif_data *emif1;
... ... @@ -1148,6 +1152,168 @@
1148 1152 return valid;
1149 1153 }
1150 1154  
  1155 +#if defined(CONFIG_OF)
  1156 +static 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 +
  1201 +static 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 +
  1235 +static 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 +
  1302 +error:
  1303 + return NULL;
  1304 +out:
  1305 + return emif;
  1306 +}
  1307 +
  1308 +#else
  1309 +
  1310 +static 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 +
1151 1317 static struct emif_data *__init_or_module get_device_details(
1152 1318 struct platform_device *pdev)
1153 1319 {
... ... @@ -1267,7 +1433,11 @@
1267 1433 struct resource *res;
1268 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 1441 if (!emif) {
1272 1442 pr_err("%s: error getting device data\n", __func__);
1273 1443 goto error;
1274 1444  
... ... @@ -1644,11 +1814,21 @@
1644 1814 spin_unlock_irqrestore(&emif_lock, irq_state);
1645 1815 }
1646 1816  
  1817 +#if defined(CONFIG_OF)
  1818 +static const struct of_device_id emif_of_match[] = {
  1819 + { .compatible = "ti,emif-4d" },
  1820 + { .compatible = "ti,emif-4d5" },
  1821 + {},
  1822 +};
  1823 +MODULE_DEVICE_TABLE(of, emif_of_match);
  1824 +#endif
  1825 +
1647 1826 static struct platform_driver emif_driver = {
1648 1827 .remove = __exit_p(emif_remove),
1649 1828 .shutdown = emif_shutdown,
1650 1829 .driver = {
1651 1830 .name = "emif",
  1831 + .of_match_table = of_match_ptr(emif_of_match),
1652 1832 },
1653 1833 };
1654 1834  
drivers/memory/of_memory.c
  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 + */
  30 +const 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 +
  59 +default_min_tck:
  60 + dev_warn(dev, "%s: using default min-tck values\n", __func__);
  61 + return &lpddr2_jedec_min_tck;
  62 +}
  63 +EXPORT_SYMBOL(of_get_min_tck);
  64 +
  65 +static 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 + */
  106 +const 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 +
  148 +default_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 +}
  153 +EXPORT_SYMBOL(of_get_ddr_timings);
drivers/memory/of_memory.h
  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
  16 +extern const struct lpddr2_min_tck *of_get_min_tck(struct device_node *np,
  17 + struct device *dev);
  18 +extern 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
  22 +static inline const struct lpddr2_min_tck
  23 + *of_get_min_tck(struct device_node *np, struct device *dev)
  24 +{
  25 + return NULL;
  26 +}
  27 +
  28 +static 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_ */