diff options
| -rw-r--r-- | Documentation/memory-devices/ti-emif.txt | 57 | ||||
| -rw-r--r-- | drivers/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/Makefile | 1 | ||||
| -rw-r--r-- | drivers/memory/Kconfig | 22 | ||||
| -rw-r--r-- | drivers/memory/Makefile | 5 | ||||
| -rw-r--r-- | drivers/memory/emif.c | 289 | ||||
| -rw-r--r-- | drivers/memory/emif.h | 7 | ||||
| -rw-r--r-- | include/linux/platform_data/emif_plat.h | 128 |
8 files changed, 511 insertions, 0 deletions
diff --git a/Documentation/memory-devices/ti-emif.txt b/Documentation/memory-devices/ti-emif.txt new file mode 100644 index 000000000000..f4ad9a7d0f4b --- /dev/null +++ b/Documentation/memory-devices/ti-emif.txt | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | TI EMIF SDRAM Controller Driver: | ||
| 2 | |||
| 3 | Author | ||
| 4 | ======== | ||
| 5 | Aneesh V <aneesh@ti.com> | ||
| 6 | |||
| 7 | Location | ||
| 8 | ============ | ||
| 9 | driver/memory/emif.c | ||
| 10 | |||
| 11 | Supported SoCs: | ||
| 12 | =================== | ||
| 13 | TI OMAP44xx | ||
| 14 | TI OMAP54xx | ||
| 15 | |||
| 16 | Menuconfig option: | ||
| 17 | ========================== | ||
| 18 | Device Drivers | ||
| 19 | Memory devices | ||
| 20 | Texas Instruments EMIF driver | ||
| 21 | |||
| 22 | Description | ||
| 23 | =========== | ||
| 24 | This driver is for the EMIF module available in Texas Instruments | ||
| 25 | SoCs. EMIF is an SDRAM controller that, based on its revision, | ||
| 26 | supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols. | ||
| 27 | This driver takes care of only LPDDR2 memories presently. The | ||
| 28 | functions of the driver includes re-configuring AC timing | ||
| 29 | parameters and other settings during frequency, voltage and | ||
| 30 | temperature changes | ||
| 31 | |||
| 32 | Platform Data (see include/linux/platform_data/emif_plat.h): | ||
| 33 | ===================================================================== | ||
| 34 | DDR device details and other board dependent and SoC dependent | ||
| 35 | information can be passed through platform data (struct emif_platform_data) | ||
| 36 | - DDR device details: 'struct ddr_device_info' | ||
| 37 | - Device AC timings: 'struct lpddr2_timings' and 'struct lpddr2_min_tck' | ||
| 38 | - Custom configurations: customizable policy options through | ||
| 39 | 'struct emif_custom_configs' | ||
| 40 | - IP revision | ||
| 41 | - PHY type | ||
| 42 | |||
| 43 | Interface to the external world: | ||
| 44 | ================================ | ||
| 45 | EMIF driver registers notifiers for voltage and frequency changes | ||
| 46 | affecting EMIF and takes appropriate actions when these are invoked. | ||
| 47 | - freq_pre_notify_handling() | ||
| 48 | - freq_post_notify_handling() | ||
| 49 | - volt_notify_handling() | ||
| 50 | |||
| 51 | Debugfs | ||
| 52 | ======== | ||
| 53 | The driver creates two debugfs entries per device. | ||
| 54 | - regcache_dump : dump of register values calculated and saved for all | ||
| 55 | frequencies used so far. | ||
| 56 | - mr4 : last polled value of MR4 register in the LPDDR2 device. MR4 | ||
| 57 | indicates the current temperature level of the device. | ||
diff --git a/drivers/Kconfig b/drivers/Kconfig index 0233ad979b7d..63b81826cb55 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
| @@ -142,4 +142,6 @@ source "drivers/devfreq/Kconfig" | |||
| 142 | 142 | ||
| 143 | source "drivers/extcon/Kconfig" | 143 | source "drivers/extcon/Kconfig" |
| 144 | 144 | ||
| 145 | source "drivers/memory/Kconfig" | ||
| 146 | |||
| 145 | endmenu | 147 | endmenu |
diff --git a/drivers/Makefile b/drivers/Makefile index c41dfa92cd79..265b506a15be 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
| @@ -135,3 +135,4 @@ obj-$(CONFIG_HYPERV) += hv/ | |||
| 135 | 135 | ||
| 136 | obj-$(CONFIG_PM_DEVFREQ) += devfreq/ | 136 | obj-$(CONFIG_PM_DEVFREQ) += devfreq/ |
| 137 | obj-$(CONFIG_EXTCON) += extcon/ | 137 | obj-$(CONFIG_EXTCON) += extcon/ |
| 138 | obj-$(CONFIG_MEMORY) += memory/ | ||
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig new file mode 100644 index 000000000000..b08327cca0e5 --- /dev/null +++ b/drivers/memory/Kconfig | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | # | ||
| 2 | # Memory devices | ||
| 3 | # | ||
| 4 | |||
| 5 | menuconfig MEMORY | ||
| 6 | bool "Memory Controller drivers" | ||
| 7 | |||
| 8 | if MEMORY | ||
| 9 | |||
| 10 | config TI_EMIF | ||
| 11 | tristate "Texas Instruments EMIF driver" | ||
| 12 | select DDR | ||
| 13 | help | ||
| 14 | This driver is for the EMIF module available in Texas Instruments | ||
| 15 | SoCs. EMIF is an SDRAM controller that, based on its revision, | ||
| 16 | supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols. | ||
| 17 | This driver takes care of only LPDDR2 memories presently. The | ||
| 18 | functions of the driver includes re-configuring AC timing | ||
| 19 | parameters and other settings during frequency, voltage and | ||
| 20 | temperature changes | ||
| 21 | |||
| 22 | endif | ||
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile new file mode 100644 index 000000000000..e27f80b28859 --- /dev/null +++ b/drivers/memory/Makefile | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | # | ||
| 2 | # Makefile for memory devices | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_TI_EMIF) += emif.o | ||
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c new file mode 100644 index 000000000000..7486d7ef0826 --- /dev/null +++ b/drivers/memory/emif.c | |||
| @@ -0,0 +1,289 @@ | |||
| 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 | */ | ||
| 42 | struct 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 | |||
| 51 | static struct emif_data *emif1; | ||
| 52 | static LIST_HEAD(device_list); | ||
| 53 | |||
| 54 | static 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 | |||
| 64 | static 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 | |||
| 93 | static 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 | |||
| 113 | static 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 | |||
| 219 | out: | ||
| 220 | return emif; | ||
| 221 | |||
| 222 | error: | ||
| 223 | return NULL; | ||
| 224 | } | ||
| 225 | |||
| 226 | static 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; | ||
| 264 | error: | ||
| 265 | return -ENODEV; | ||
| 266 | } | ||
| 267 | |||
| 268 | static struct platform_driver emif_driver = { | ||
| 269 | .driver = { | ||
| 270 | .name = "emif", | ||
| 271 | }, | ||
| 272 | }; | ||
| 273 | |||
| 274 | static int __init_or_module emif_register(void) | ||
| 275 | { | ||
| 276 | return platform_driver_probe(&emif_driver, emif_probe); | ||
| 277 | } | ||
| 278 | |||
| 279 | static void __exit emif_unregister(void) | ||
| 280 | { | ||
| 281 | platform_driver_unregister(&emif_driver); | ||
| 282 | } | ||
| 283 | |||
| 284 | module_init(emif_register); | ||
| 285 | module_exit(emif_unregister); | ||
| 286 | MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver"); | ||
| 287 | MODULE_LICENSE("GPL"); | ||
| 288 | MODULE_ALIAS("platform:emif"); | ||
| 289 | MODULE_AUTHOR("Texas Instruments Inc"); | ||
diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h index 44b97dfe95b4..692b2a864e7b 100644 --- a/drivers/memory/emif.h +++ b/drivers/memory/emif.h | |||
| @@ -12,6 +12,13 @@ | |||
| 12 | #ifndef __EMIF_H | 12 | #ifndef __EMIF_H |
| 13 | #define __EMIF_H | 13 | #define __EMIF_H |
| 14 | 14 | ||
| 15 | /* | ||
| 16 | * Maximum number of different frequencies supported by EMIF driver | ||
| 17 | * Determines the number of entries in the pointer array for register | ||
| 18 | * cache | ||
| 19 | */ | ||
| 20 | #define EMIF_MAX_NUM_FREQUENCIES 6 | ||
| 21 | |||
| 15 | /* Registers offset */ | 22 | /* Registers offset */ |
| 16 | #define EMIF_MODULE_ID_AND_REVISION 0x0000 | 23 | #define EMIF_MODULE_ID_AND_REVISION 0x0000 |
| 17 | #define EMIF_STATUS 0x0004 | 24 | #define EMIF_STATUS 0x0004 |
diff --git a/include/linux/platform_data/emif_plat.h b/include/linux/platform_data/emif_plat.h new file mode 100644 index 000000000000..03378ca84061 --- /dev/null +++ b/include/linux/platform_data/emif_plat.h | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | /* | ||
| 2 | * Definitions for TI EMIF device platform data | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Texas Instruments, Inc. | ||
| 5 | * | ||
| 6 | * Aneesh V <aneesh@ti.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | */ | ||
| 12 | #ifndef __EMIF_PLAT_H | ||
| 13 | #define __EMIF_PLAT_H | ||
| 14 | |||
| 15 | /* Low power modes - EMIF_PWR_MGMT_CTRL */ | ||
| 16 | #define EMIF_LP_MODE_DISABLE 0 | ||
| 17 | #define EMIF_LP_MODE_CLOCK_STOP 1 | ||
| 18 | #define EMIF_LP_MODE_SELF_REFRESH 2 | ||
| 19 | #define EMIF_LP_MODE_PWR_DN 4 | ||
| 20 | |||
| 21 | /* Hardware capabilities */ | ||
| 22 | #define EMIF_HW_CAPS_LL_INTERFACE 0x00000001 | ||
| 23 | |||
| 24 | /* | ||
| 25 | * EMIF IP Revisions | ||
| 26 | * EMIF4D - Used in OMAP4 | ||
| 27 | * EMIF4D5 - Used in OMAP5 | ||
| 28 | */ | ||
| 29 | #define EMIF_4D 1 | ||
| 30 | #define EMIF_4D5 2 | ||
| 31 | |||
| 32 | /* | ||
| 33 | * PHY types | ||
| 34 | * ATTILAPHY - Used in OMAP4 | ||
| 35 | * INTELLIPHY - Used in OMAP5 | ||
| 36 | */ | ||
| 37 | #define EMIF_PHY_TYPE_ATTILAPHY 1 | ||
| 38 | #define EMIF_PHY_TYPE_INTELLIPHY 2 | ||
| 39 | |||
| 40 | /* Custom config requests */ | ||
| 41 | #define EMIF_CUSTOM_CONFIG_LPMODE 0x00000001 | ||
| 42 | #define EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL 0x00000002 | ||
| 43 | |||
| 44 | #ifndef __ASSEMBLY__ | ||
| 45 | /** | ||
| 46 | * struct ddr_device_info - All information about the DDR device except AC | ||
| 47 | * timing parameters | ||
| 48 | * @type: Device type (LPDDR2-S4, LPDDR2-S2 etc) | ||
| 49 | * @density: Device density | ||
| 50 | * @io_width: Bus width | ||
| 51 | * @cs1_used: Whether there is a DDR device attached to the second | ||
| 52 | * chip-select(CS1) of this EMIF instance | ||
| 53 | * @cal_resistors_per_cs: Whether there is one calibration resistor per | ||
| 54 | * chip-select or whether it's a single one for both | ||
| 55 | * @manufacturer: Manufacturer name string | ||
| 56 | */ | ||
| 57 | struct ddr_device_info { | ||
| 58 | u32 type; | ||
| 59 | u32 density; | ||
| 60 | u32 io_width; | ||
| 61 | u32 cs1_used; | ||
| 62 | u32 cal_resistors_per_cs; | ||
| 63 | char manufacturer[10]; | ||
| 64 | }; | ||
| 65 | |||
| 66 | /** | ||
| 67 | * struct emif_custom_configs - Custom configuration parameters/policies | ||
| 68 | * passed from the platform layer | ||
| 69 | * @mask: Mask to indicate which configs are requested | ||
| 70 | * @lpmode: LPMODE to be used in PWR_MGMT_CTRL register | ||
| 71 | * @lpmode_timeout_performance: Timeout before LPMODE entry when higher | ||
| 72 | * performance is desired at the cost of power (typically | ||
| 73 | * at higher OPPs) | ||
| 74 | * @lpmode_timeout_power: Timeout before LPMODE entry when better power | ||
| 75 | * savings is desired and performance is not important | ||
| 76 | * (typically at lower loads indicated by lower OPPs) | ||
| 77 | * @lpmode_freq_threshold: The DDR frequency threshold to identify between | ||
| 78 | * the above two cases: | ||
| 79 | * timeout = (freq >= lpmode_freq_threshold) ? | ||
| 80 | * lpmode_timeout_performance : | ||
| 81 | * lpmode_timeout_power; | ||
| 82 | * @temp_alert_poll_interval_ms: LPDDR2 MR4 polling interval at nominal | ||
| 83 | * temperature(in milliseconds). When temperature is high | ||
| 84 | * polling is done 4 times as frequently. | ||
| 85 | */ | ||
| 86 | struct emif_custom_configs { | ||
| 87 | u32 mask; | ||
| 88 | u32 lpmode; | ||
| 89 | u32 lpmode_timeout_performance; | ||
| 90 | u32 lpmode_timeout_power; | ||
| 91 | u32 lpmode_freq_threshold; | ||
| 92 | u32 temp_alert_poll_interval_ms; | ||
| 93 | }; | ||
| 94 | |||
| 95 | /** | ||
| 96 | * struct emif_platform_data - Platform data passed on EMIF platform | ||
| 97 | * device creation. Used by the driver. | ||
| 98 | * @hw_caps: Hw capabilities of the EMIF IP in the respective SoC | ||
| 99 | * @device_info: Device info structure containing information such | ||
| 100 | * as type, bus width, density etc | ||
| 101 | * @timings: Timings information from device datasheet passed | ||
| 102 | * as an array of 'struct lpddr2_timings'. Can be NULL | ||
| 103 | * if if default timings are ok | ||
| 104 | * @timings_arr_size: Size of the timings array. Depends on the number | ||
| 105 | * of different frequencies for which timings data | ||
| 106 | * is provided | ||
| 107 | * @min_tck: Minimum value of some timing parameters in terms | ||
| 108 | * of number of cycles. Can be NULL if default values | ||
| 109 | * are ok | ||
| 110 | * @custom_configs: Custom configurations requested by SoC or board | ||
| 111 | * code and the data for them. Can be NULL if default | ||
| 112 | * configurations done by the driver are ok. See | ||
| 113 | * documentation for 'struct emif_custom_configs' for | ||
| 114 | * more details | ||
| 115 | */ | ||
| 116 | struct emif_platform_data { | ||
| 117 | u32 hw_caps; | ||
| 118 | struct ddr_device_info *device_info; | ||
| 119 | const struct lpddr2_timings *timings; | ||
| 120 | u32 timings_arr_size; | ||
| 121 | const struct lpddr2_min_tck *min_tck; | ||
| 122 | struct emif_custom_configs *custom_configs; | ||
| 123 | u32 ip_rev; | ||
| 124 | u32 phy_type; | ||
| 125 | }; | ||
| 126 | #endif /* __ASSEMBLY__ */ | ||
| 127 | |||
| 128 | #endif /* __LINUX_EMIF_H */ | ||
