diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/memory/Makefile | 1 | ||||
-rw-r--r-- | drivers/memory/emif.c | 182 | ||||
-rw-r--r-- | drivers/memory/of_memory.c | 153 | ||||
-rw-r--r-- | drivers/memory/of_memory.h | 36 |
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 | ||
5 | obj-$(CONFIG_OF) += of_memory.o | ||
5 | obj-$(CONFIG_TI_EMIF) += emif.o | 6 | obj-$(CONFIG_TI_EMIF) += emif.o |
6 | obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o | 7 | obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o |
7 | obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o | 8 | obj-$(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 | */ |
53 | struct emif_data { | 56 | struct 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 | ||
68 | static struct emif_data *emif1; | 72 | static 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) | ||
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 | static struct emif_data *__init_or_module get_device_details( | 1317 | static 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) | ||
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 | static struct platform_driver emif_driver = { | 1826 | static 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 | */ | ||
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); | ||
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 | ||
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_ */ | ||