blob: d31f3c40a00e2e2717bbc7051f152ff3c42c8061 [file] [log] [blame]
Neeti Desaicfa35b12012-12-12 14:40:59 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070013#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/mm.h>
17#include <linux/rbtree.h>
18#include <linux/genalloc.h>
19#include <linux/of.h>
Naveen Ramaraj8ad63602012-05-09 20:50:39 -070020#include <linux/of_address.h>
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070021#include <linux/io.h>
22#include <linux/platform_device.h>
23#include <linux/debugfs.h>
24#include <linux/seq_file.h>
Naveen Ramaraj8ad63602012-05-09 20:50:39 -070025#include <mach/ocmem_priv.h>
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070026
Naveen Ramaraj5b0982b2012-06-20 23:02:33 -070027#define OCMEM_REGION_CTL_BASE 0xFDD0003C
Naveen Ramaraj1ebbfad2012-07-20 19:05:59 -070028#define OCMEM_REGION_CTL_SIZE 0xFD0
Naveen Ramaraj1ebbfad2012-07-20 19:05:59 -070029#define GRAPHICS_REGION_CTL (0x17F000)
Naveen Ramaraj5b0982b2012-06-20 23:02:33 -070030
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070031struct ocmem_partition {
32 const char *name;
33 int id;
34 unsigned long p_start;
35 unsigned long p_size;
36 unsigned long p_min;
Naveen Ramaraj135cd672012-04-23 12:13:28 -070037 unsigned int p_tail;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070038};
39
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070040struct ocmem_zone zones[OCMEM_CLIENT_MAX];
41
42struct ocmem_zone *get_zone(unsigned id)
43{
44 if (id < OCMEM_GRAPHICS || id >= OCMEM_CLIENT_MAX)
45 return NULL;
46 else
47 return &zones[id];
48}
49
50static struct ocmem_plat_data *ocmem_pdata;
51
52#define CLIENT_NAME_MAX 10
Naveen Ramarajcc4ec152012-05-14 09:55:29 -070053
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070054/* Must be in sync with enum ocmem_client */
55static const char *client_names[OCMEM_CLIENT_MAX] = {
56 "graphics",
57 "video",
58 "camera",
59 "hp_audio",
60 "voice",
61 "lp_audio",
62 "sensors",
Naveen Ramarajcc4ec152012-05-14 09:55:29 -070063 "other_os",
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070064};
65
Naveen Ramaraj6a92b262012-07-30 17:36:24 -070066/* Must be in sync with enum ocmem_zstat_item */
67static const char *zstat_names[NR_OCMEM_ZSTAT_ITEMS] = {
68 "Allocation requests",
69 "Synchronous allocations",
70 "Ranged allocations",
71 "Asynchronous allocations",
72 "Allocation failures",
73 "Allocations grown",
74 "Allocations freed",
75 "Allocations shrunk",
76 "OCMEM maps",
77 "Map failures",
78 "OCMEM unmaps",
79 "Unmap failures",
80 "Transfers to OCMEM",
81 "Transfers to DDR",
82 "Transfer failures",
83 "Evictions",
84 "Restorations",
Naveen Ramaraj55ed8902012-09-26 13:18:06 -070085 "Dump requests",
86 "Dump completed",
Naveen Ramaraj6a92b262012-07-30 17:36:24 -070087};
88
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070089struct ocmem_quota_table {
90 const char *name;
91 int id;
92 unsigned long start;
93 unsigned long size;
94 unsigned long min;
Naveen Ramaraj135cd672012-04-23 12:13:28 -070095 unsigned int tail;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070096};
97
98/* This static table will go away with device tree support */
99static struct ocmem_quota_table qt[OCMEM_CLIENT_MAX] = {
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700100 /* name, id, start, size, min, tail */
101 { "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000, 0},
102 { "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000, 1},
103 { "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0, 0},
104 { "voice", OCMEM_VOICE, 0x0, 0x0, 0x0, 0 },
105 { "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0, 0},
106 { "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000, 0},
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700107 { "other_os", OCMEM_OTHER_OS, 0x120000, 0x20000, 0x20000, 0},
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700108 { "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000, 0},
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700109};
110
111static inline int get_id(const char *name)
112{
113 int i = 0;
114 for (i = 0 ; i < OCMEM_CLIENT_MAX; i++) {
115 if (strncmp(name, client_names[i], CLIENT_NAME_MAX) == 0)
116 return i;
117 }
118 return -EINVAL;
119}
120
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700121int check_id(int id)
122{
123 return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
124}
125
126const char *get_name(int id)
127{
128 if (!check_id(id))
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700129 return "Unknown";
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700130 return client_names[id];
131}
132
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700133inline unsigned long phys_to_offset(unsigned long addr)
134{
135 if (!ocmem_pdata)
136 return 0;
137 if (addr < ocmem_pdata->base ||
138 addr > (ocmem_pdata->base + ocmem_pdata->size))
139 return 0;
140 return addr - ocmem_pdata->base;
141}
142
143inline unsigned long offset_to_phys(unsigned long offset)
144{
145 if (!ocmem_pdata)
146 return 0;
147 if (offset > ocmem_pdata->size)
148 return 0;
149 return offset + ocmem_pdata->base;
150}
151
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700152inline int zone_active(int id)
153{
154 struct ocmem_zone *z = get_zone(id);
155 if (z)
156 return z->active == true ? 1 : 0;
157 else
158 return 0;
159}
160
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700161inline void inc_ocmem_stat(struct ocmem_zone *z,
162 enum ocmem_zstat_item item)
163{
164 if (!z)
165 return;
166 atomic_long_inc(&z->z_stat[item]);
167}
168
169inline unsigned long get_ocmem_stat(struct ocmem_zone *z,
170 enum ocmem_zstat_item item)
171{
172 if (!z)
173 return 0;
174 else
175 return atomic_long_read(&z->z_stat[item]);
176}
177
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700178static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
179{
180 struct ocmem_plat_data *pdata = NULL;
181 struct ocmem_partition *parts = NULL;
182 struct device *dev = &pdev->dev;
Naveen Ramaraje653c2b2012-05-30 12:59:25 -0700183 unsigned nr_parts = 0;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700184 int i;
185 int j;
186
187 pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
188 GFP_KERNEL);
189
190 if (!pdata) {
191 dev_err(dev, "Unable to allocate memory for"
192 " platform data\n");
193 return NULL;
194 }
195
196 for (i = 0 ; i < ARRAY_SIZE(qt); i++)
197 if (qt[i].size != 0x0)
198 nr_parts++;
199
200 if (nr_parts == 0x0) {
201 dev_err(dev, "No valid ocmem partitions\n");
202 return NULL;
203 } else
204 dev_info(dev, "Total partitions = %d\n", nr_parts);
205
206 parts = devm_kzalloc(dev, sizeof(struct ocmem_partition) * nr_parts,
207 GFP_KERNEL);
208
209 if (!parts) {
210 dev_err(dev, "Unable to allocate memory for"
211 " partition data\n");
212 return NULL;
213 }
214
215 for (i = 0, j = 0; i < ARRAY_SIZE(qt); i++) {
216 if (qt[i].size == 0x0) {
217 dev_dbg(dev, "Skipping creation of pool for %s\n",
218 qt[i].name);
219 continue;
220 }
221 parts[j].id = qt[i].id;
222 parts[j].p_size = qt[i].size;
223 parts[j].p_start = qt[i].start;
224 parts[j].p_min = qt[i].min;
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700225 parts[j].p_tail = qt[i].tail;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700226 j++;
227 }
228 BUG_ON(j != nr_parts);
229 pdata->nr_parts = nr_parts;
230 pdata->parts = parts;
231 pdata->base = OCMEM_PHYS_BASE;
232 pdata->size = OCMEM_PHYS_SIZE;
233 return pdata;
234}
235
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700236int __devinit of_ocmem_parse_regions(struct device *dev,
237 struct ocmem_partition **part)
238{
239 const char *name;
240 struct device_node *child = NULL;
241 int nr_parts = 0;
242 int i = 0;
243 int rc = 0;
244 int id = -1;
245
246 /*Compute total partitions */
247 for_each_child_of_node(dev->of_node, child)
248 nr_parts++;
249
250 if (nr_parts == 0)
251 return 0;
252
253 *part = devm_kzalloc(dev, nr_parts * sizeof(**part),
254 GFP_KERNEL);
255
256 if (!*part)
257 return -ENOMEM;
258
259 for_each_child_of_node(dev->of_node, child)
260 {
261 const u32 *addr;
262 u32 min;
263 u64 size;
264 u64 p_start;
265
266 addr = of_get_address(child, 0, &size, NULL);
267
268 if (!addr) {
269 dev_err(dev, "Invalid addr for partition %d, ignored\n",
270 i);
271 continue;
272 }
273
274 rc = of_property_read_u32(child, "qcom,ocmem-part-min", &min);
275
276 if (rc) {
277 dev_err(dev, "No min for partition %d, ignored\n", i);
278 continue;
279 }
280
281 rc = of_property_read_string(child, "qcom,ocmem-part-name",
282 &name);
283
284 if (rc) {
285 dev_err(dev, "No name for partition %d, ignored\n", i);
286 continue;
287 }
288
289 id = get_id(name);
290
291 if (id < 0) {
292 dev_err(dev, "Ignoring invalid partition %s\n", name);
293 continue;
294 }
295
296 p_start = of_translate_address(child, addr);
297
298 if (p_start == OF_BAD_ADDR) {
299 dev_err(dev, "Invalid offset for partition %d\n", i);
300 continue;
301 }
302
303 (*part)[i].p_start = p_start;
304 (*part)[i].p_size = size;
305 (*part)[i].id = id;
306 (*part)[i].name = name;
307 (*part)[i].p_min = min;
308 (*part)[i].p_tail = of_property_read_bool(child, "tail");
309 i++;
310 }
311
312 return i;
313}
314
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700315#if defined(CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL)
316static int parse_power_ctrl_config(struct ocmem_plat_data *pdata,
317 struct device_node *node)
318{
319 pdata->rpm_pwr_ctrl = false;
320 pdata->rpm_rsc_type = ~0x0;
321 return 0;
322}
323#else
324static int parse_power_ctrl_config(struct ocmem_plat_data *pdata,
325 struct device_node *node)
326{
327 unsigned rsc_type = ~0x0;
328 pdata->rpm_pwr_ctrl = false;
329 if (of_property_read_u32(node, "qcom,resource-type",
330 &rsc_type))
331 return -EINVAL;
332 pdata->rpm_pwr_ctrl = true;
333 pdata->rpm_rsc_type = rsc_type;
334 return 0;
335
336}
337#endif /* CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL */
338
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700339/* Core Clock Operations */
340int ocmem_enable_core_clock(void)
341{
342 int ret;
343 ret = clk_prepare_enable(ocmem_pdata->core_clk);
344 if (ret) {
345 pr_err("ocmem: Failed to enable core clock\n");
346 return ret;
347 }
348 pr_debug("ocmem: Enabled core clock\n");
349 return 0;
350}
351
352void ocmem_disable_core_clock(void)
353{
354 clk_disable_unprepare(ocmem_pdata->core_clk);
355 pr_debug("ocmem: Disabled core clock\n");
356}
357
358/* Branch Clock Operations */
359int ocmem_enable_iface_clock(void)
360{
361 int ret;
Neeti Desai8297364b2013-02-05 17:16:36 -0800362
363 if (!ocmem_pdata->iface_clk)
364 return 0;
365
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700366 ret = clk_prepare_enable(ocmem_pdata->iface_clk);
367 if (ret) {
Neeti Desai8297364b2013-02-05 17:16:36 -0800368 pr_err("ocmem: Failed to disable iface clock\n");
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700369 return ret;
370 }
371 pr_debug("ocmem: Enabled iface clock\n");
372 return 0;
373}
374
375void ocmem_disable_iface_clock(void)
376{
Neeti Desai8297364b2013-02-05 17:16:36 -0800377 if (!ocmem_pdata->iface_clk)
378 return;
379
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700380 clk_disable_unprepare(ocmem_pdata->iface_clk);
381 pr_debug("ocmem: Disabled iface clock\n");
382}
383
Neeti Desaiff663962012-11-20 15:32:13 -0800384static struct ocmem_plat_data * __devinit parse_dt_config
385 (struct platform_device *pdev)
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700386{
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700387 struct device *dev = &pdev->dev;
388 struct device_node *node = pdev->dev.of_node;
389 struct ocmem_plat_data *pdata = NULL;
390 struct ocmem_partition *parts = NULL;
391 struct resource *ocmem_irq;
392 struct resource *dm_irq;
393 struct resource *ocmem_mem;
394 struct resource *reg_base;
395 struct resource *br_base;
396 struct resource *dm_base;
397 struct resource *ocmem_mem_io;
398 unsigned nr_parts = 0;
399 unsigned nr_regions = 0;
Neeti Desaicfa35b12012-12-12 14:40:59 -0800400 unsigned nr_macros = 0;
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700401
402 pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
403 GFP_KERNEL);
404
405 if (!pdata) {
406 dev_err(dev, "Unable to allocate memory for platform data\n");
407 return NULL;
408 }
409
410 ocmem_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
411 "ocmem_physical");
412 if (!ocmem_mem) {
413 dev_err(dev, "No OCMEM memory resource\n");
414 return NULL;
415 }
416
417 ocmem_mem_io = request_mem_region(ocmem_mem->start,
418 resource_size(ocmem_mem), pdev->name);
419
420 if (!ocmem_mem_io) {
421 dev_err(dev, "Could not claim OCMEM memory\n");
422 return NULL;
423 }
424
425 pdata->base = ocmem_mem->start;
426 pdata->size = resource_size(ocmem_mem);
427 pdata->vbase = devm_ioremap_nocache(dev, ocmem_mem->start,
428 resource_size(ocmem_mem));
429 if (!pdata->vbase) {
430 dev_err(dev, "Could not ioremap ocmem memory\n");
431 return NULL;
432 }
433
434 reg_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
435 "ocmem_ctrl_physical");
436 if (!reg_base) {
437 dev_err(dev, "No OCMEM register resource\n");
438 return NULL;
439 }
440
441 pdata->reg_base = devm_ioremap_nocache(dev, reg_base->start,
442 resource_size(reg_base));
443 if (!pdata->reg_base) {
444 dev_err(dev, "Could not ioremap register map\n");
445 return NULL;
446 }
447
448 br_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
449 "br_ctrl_physical");
450 if (!br_base) {
451 dev_err(dev, "No OCMEM BR resource\n");
452 return NULL;
453 }
454
455 pdata->br_base = devm_ioremap_nocache(dev, br_base->start,
456 resource_size(br_base));
457 if (!pdata->br_base) {
458 dev_err(dev, "Could not ioremap BR resource\n");
459 return NULL;
460 }
461
462 dm_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
463 "dm_ctrl_physical");
464 if (!dm_base) {
465 dev_err(dev, "No OCMEM DM resource\n");
466 return NULL;
467 }
468
469 pdata->dm_base = devm_ioremap_nocache(dev, dm_base->start,
470 resource_size(dm_base));
471 if (!pdata->dm_base) {
472 dev_err(dev, "Could not ioremap DM resource\n");
473 return NULL;
474 }
475
476 ocmem_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
477 "ocmem_irq");
478
479 if (!ocmem_irq) {
480 dev_err(dev, "No OCMEM IRQ resource\n");
481 return NULL;
482 }
483
484 dm_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
485 "dm_irq");
486
487 if (!dm_irq) {
488 dev_err(dev, "No DM IRQ resource\n");
489 return NULL;
490 }
491
492 if (of_property_read_u32(node, "qcom,ocmem-num-regions",
493 &nr_regions)) {
494 dev_err(dev, "No OCMEM memory regions specified\n");
495 }
496
497 if (nr_regions == 0) {
498 dev_err(dev, "No hardware memory regions found\n");
499 return NULL;
500 }
501
Neeti Desaicfa35b12012-12-12 14:40:59 -0800502 if (of_property_read_u32(node, "qcom,ocmem-num-macros",
503 &nr_macros)) {
504 dev_err(dev, "No OCMEM macros specified\n");
505 }
506
507 if (nr_macros == 0) {
508 dev_err(dev, "No hardware macros found\n");
509 return NULL;
510 }
511
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700512 /* Figure out the number of partititons */
513 nr_parts = of_ocmem_parse_regions(dev, &parts);
514 if (nr_parts <= 0) {
515 dev_err(dev, "No valid OCMEM partitions found\n");
516 goto pdata_error;
517 } else
518 dev_dbg(dev, "Found %d ocmem partitions\n", nr_parts);
519
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700520 if (parse_power_ctrl_config(pdata, node)) {
521 dev_err(dev, "No OCMEM RPM Resource specified\n");
522 return NULL;
523 }
524
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700525 pdata->nr_parts = nr_parts;
526 pdata->parts = parts;
527 pdata->nr_regions = nr_regions;
Neeti Desaicfa35b12012-12-12 14:40:59 -0800528 pdata->nr_macros = nr_macros;
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700529 pdata->ocmem_irq = ocmem_irq->start;
530 pdata->dm_irq = dm_irq->start;
531 return pdata;
532pdata_error:
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700533 return NULL;
534}
535
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700536static int ocmem_zones_show(struct seq_file *f, void *dummy)
537{
538 unsigned i = 0;
539 for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
540 struct ocmem_zone *z = get_zone(i);
541 if (z && z->active == true)
542 seq_printf(f, "zone %s\t:0x%08lx - 0x%08lx (%4ld KB)\n",
543 get_name(z->owner), z->z_start, z->z_end - 1,
544 (z->z_end - z->z_start)/SZ_1K);
545 }
546 return 0;
547}
548
549static int ocmem_zones_open(struct inode *inode, struct file *file)
550{
551 return single_open(file, ocmem_zones_show, inode->i_private);
552}
553
554static const struct file_operations zones_show_fops = {
555 .open = ocmem_zones_open,
556 .read = seq_read,
557 .llseek = seq_lseek,
558 .release = seq_release,
559};
560
561static int ocmem_stats_show(struct seq_file *f, void *dummy)
562{
563 unsigned i = 0;
564 unsigned j = 0;
565 for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
566 struct ocmem_zone *z = get_zone(i);
567 if (z && z->active == true) {
568 seq_printf(f, "zone %s:\n", get_name(z->owner));
569 for (j = 0 ; j < ARRAY_SIZE(zstat_names); j++) {
570 seq_printf(f, "\t %s: %lu\n", zstat_names[j],
571 get_ocmem_stat(z, j));
572 }
573 }
574 }
575 return 0;
576}
577
578static int ocmem_stats_open(struct inode *inode, struct file *file)
579{
580 return single_open(file, ocmem_stats_show, inode->i_private);
581}
582
583static const struct file_operations stats_show_fops = {
584 .open = ocmem_stats_open,
585 .read = seq_read,
586 .llseek = seq_lseek,
587 .release = seq_release,
588};
589
Neeti Desaif69aa132013-02-28 17:25:01 -0800590static int ocmem_timing_show(struct seq_file *f, void *dummy)
591{
592 unsigned i = 0;
593 for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
594 struct ocmem_zone *z = get_zone(i);
595 if (z && z->active == true)
596 seq_printf(f, "zone %s\t: alloc_delay:[max:%d, min:%d, total:%llu,cnt:%lu] free_delay:[max:%d, min:%d, total:%llu, cnt:%lu]\n",
597 get_name(z->owner), z->max_alloc_time,
598 z->min_alloc_time, z->total_alloc_time,
599 get_ocmem_stat(z, 1), z->max_free_time,
600 z->min_free_time, z->total_free_time,
601 get_ocmem_stat(z, 6));
602 }
603 return 0;
604}
605
606static int ocmem_timing_open(struct inode *inode, struct file *file)
607{
608 return single_open(file, ocmem_timing_show, inode->i_private);
609}
610
611static const struct file_operations timing_show_fops = {
612 .open = ocmem_timing_open,
613 .read = seq_read,
614 .llseek = seq_lseek,
615 .release = seq_release,
616};
617
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700618static int ocmem_zone_init(struct platform_device *pdev)
619{
620
621 int ret = -1;
622 int i = 0;
623 unsigned active_zones = 0;
624
625 struct ocmem_zone *zone = NULL;
626 struct ocmem_zone_ops *z_ops = NULL;
627 struct device *dev = &pdev->dev;
628 unsigned long start;
629 struct ocmem_plat_data *pdata = NULL;
630
631 pdata = platform_get_drvdata(pdev);
632
633 for (i = 0; i < pdata->nr_parts; i++) {
634 struct ocmem_partition *part = &pdata->parts[i];
635 zone = get_zone(part->id);
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700636 zone->active = false;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700637
638 dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
639 i, part->p_start, part->p_size,
640 client_names[part->id]);
641
642 if (part->p_size > pdata->size) {
643 dev_alert(dev, "Quota > ocmem_size for id:%d\n",
644 part->id);
645 continue;
646 }
647
648 zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
649
650 if (!zone->z_pool) {
651 dev_alert(dev, "Creating pool failed for id:%d\n",
652 part->id);
653 return -EBUSY;
654 }
655
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700656 start = part->p_start;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700657 ret = gen_pool_add(zone->z_pool, start,
658 part->p_size, -1);
659
660 if (ret < 0) {
661 gen_pool_destroy(zone->z_pool);
662 dev_alert(dev, "Unable to back pool %d with "
663 "buffer:%lx\n", part->id, part->p_size);
664 return -EBUSY;
665 }
666
667 /* Initialize zone allocators */
668 z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
669 GFP_KERNEL);
670 if (!z_ops) {
671 pr_alert("ocmem: Unable to allocate memory for"
672 "zone ops:%d\n", i);
673 return -EBUSY;
674 }
675
676 /* Initialize zone parameters */
677 zone->z_start = start;
678 zone->z_head = zone->z_start;
679 zone->z_end = start + part->p_size;
680 zone->z_tail = zone->z_end;
681 zone->z_free = part->p_size;
682 zone->owner = part->id;
683 zone->active_regions = 0;
684 zone->max_regions = 0;
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700685 INIT_LIST_HEAD(&zone->req_list);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700686 zone->z_ops = z_ops;
Neeti Desaif69aa132013-02-28 17:25:01 -0800687 zone->max_alloc_time = 0;
688 zone->min_alloc_time = 0xFFFFFFFF;
689 zone->total_alloc_time = 0;
690 zone->max_free_time = 0;
691 zone->min_free_time = 0xFFFFFFFF;
692 zone->total_free_time = 0;
693
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700694 if (part->p_tail) {
695 z_ops->allocate = allocate_tail;
696 z_ops->free = free_tail;
697 } else {
698 z_ops->allocate = allocate_head;
699 z_ops->free = free_head;
700 }
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700701 /* zap the counters */
702 memset(zone->z_stat, 0 , sizeof(zone->z_stat));
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700703 zone->active = true;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700704 active_zones++;
705
706 if (active_zones == 1)
707 pr_info("Physical OCMEM zone layout:\n");
708
709 pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
710 client_names[part->id], zone->z_start,
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700711 zone->z_end - 1, part->p_size/SZ_1K);
712 }
713
714 if (!debugfs_create_file("zones", S_IRUGO, pdata->debug_node,
715 NULL, &zones_show_fops)) {
716 dev_err(dev, "Unable to create debugfs node for zones\n");
717 return -EBUSY;
718 }
719
720 if (!debugfs_create_file("stats", S_IRUGO, pdata->debug_node,
721 NULL, &stats_show_fops)) {
722 dev_err(dev, "Unable to create debugfs node for stats\n");
723 return -EBUSY;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700724 }
725
Neeti Desaif69aa132013-02-28 17:25:01 -0800726 if (!debugfs_create_file("timing", S_IRUGO, pdata->debug_node,
727 NULL, &timing_show_fops)) {
728 dev_err(dev, "Unable to create debugfs node for timing\n");
729 return -EBUSY;
730 }
731
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700732 dev_dbg(dev, "Total active zones = %d\n", active_zones);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700733 return 0;
734}
735
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700736/* Enable the ocmem graphics mpU as a workaround */
Naveen Ramaraje4cc4622012-10-29 17:28:57 -0700737#ifdef CONFIG_MSM_OCMEM_NONSECURE
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700738static int ocmem_init_gfx_mpu(struct platform_device *pdev)
739{
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700740 int rc;
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700741 struct device *dev = &pdev->dev;
742 void __iomem *ocmem_region_vbase = NULL;
743
744 ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
745 OCMEM_REGION_CTL_SIZE);
746 if (!ocmem_region_vbase)
747 return -EBUSY;
748
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700749 rc = ocmem_enable_core_clock();
750
751 if (rc < 0)
752 return rc;
753
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700754 writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700755 ocmem_disable_core_clock();
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700756 return 0;
757}
Naveen Ramaraje4cc4622012-10-29 17:28:57 -0700758#else
759static int ocmem_init_gfx_mpu(struct platform_device *pdev)
760{
761 return 0;
762}
763#endif /* CONFIG_MSM_OCMEM_NONSECURE */
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700764
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700765static int __devinit ocmem_debugfs_init(struct platform_device *pdev)
766{
767 struct dentry *debug_dir = NULL;
768 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
769
770 debug_dir = debugfs_create_dir("ocmem", NULL);
771 if (!debug_dir || IS_ERR(debug_dir)) {
772 pr_err("ocmem: Unable to create debugfs root\n");
773 return PTR_ERR(debug_dir);
774 }
775
776 pdata->debug_node = debug_dir;
777 return 0;
778}
779
780static void __devexit ocmem_debugfs_exit(struct platform_device *pdev)
781{
782 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
783 debugfs_remove_recursive(pdata->debug_node);
784}
785
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700786static int __devinit msm_ocmem_probe(struct platform_device *pdev)
787{
788 struct device *dev = &pdev->dev;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700789 struct clk *ocmem_core_clk = NULL;
790 struct clk *ocmem_iface_clk = NULL;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700791
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700792 if (!pdev->dev.of_node) {
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700793 dev_info(dev, "Missing Configuration in Device Tree\n");
794 ocmem_pdata = parse_static_config(pdev);
795 } else {
796 ocmem_pdata = parse_dt_config(pdev);
797 }
798
799 /* Check if we have some configuration data to start */
800 if (!ocmem_pdata)
801 return -ENODEV;
802
803 /* Sanity Checks */
804 BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
805 BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
806
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700807 dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
808
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700809 ocmem_core_clk = devm_clk_get(dev, "core_clk");
810
811 if (IS_ERR(ocmem_core_clk)) {
812 dev_err(dev, "Unable to get the core clock\n");
813 return PTR_ERR(ocmem_core_clk);
814 }
815
816 /* The core clock is synchronous with graphics */
817 if (clk_set_rate(ocmem_core_clk, 1000) < 0) {
818 dev_err(dev, "Set rate failed on the core clock\n");
819 return -EBUSY;
820 }
821
822 ocmem_iface_clk = devm_clk_get(dev, "iface_clk");
823
Neeti Desai8297364b2013-02-05 17:16:36 -0800824 if (IS_ERR_OR_NULL(ocmem_iface_clk))
825 ocmem_iface_clk = NULL;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700826
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700827
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700828 ocmem_pdata->core_clk = ocmem_core_clk;
829 ocmem_pdata->iface_clk = ocmem_iface_clk;
830
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700831 platform_set_drvdata(pdev, ocmem_pdata);
832
Naveen Ramaraje4cc4622012-10-29 17:28:57 -0700833 /* Parameter to be updated based on TZ */
834 /* Allow the OCMEM CSR to be programmed */
835 if (ocmem_enable_sec_program(OCMEM_SECURE_DEV_ID))
836 return -EBUSY;
837
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700838 if (ocmem_debugfs_init(pdev))
839 return -EBUSY;
840
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700841 if (ocmem_core_init(pdev))
842 return -EBUSY;
843
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700844 if (ocmem_zone_init(pdev))
845 return -EBUSY;
846
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -0700847 if (ocmem_notifier_init())
848 return -EBUSY;
849
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700850 if (ocmem_sched_init(pdev))
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700851 return -EBUSY;
Naveen Ramaraj5b0982b2012-06-20 23:02:33 -0700852
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700853 if (ocmem_rdm_init(pdev))
854 return -EBUSY;
855
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700856 if (ocmem_init_gfx_mpu(pdev)) {
857 dev_err(dev, "Unable to initialize Graphics mPU\n");
858 return -EBUSY;
859 }
860
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700861 dev_dbg(dev, "initialized successfully\n");
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700862 return 0;
863}
864
865static int __devexit msm_ocmem_remove(struct platform_device *pdev)
866{
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700867 ocmem_debugfs_exit(pdev);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700868 return 0;
869}
870
871static struct of_device_id msm_ocmem_dt_match[] = {
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700872 { .compatible = "qcom,msm-ocmem",
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700873 },
874 {}
875};
876
877static struct platform_driver msm_ocmem_driver = {
878 .probe = msm_ocmem_probe,
879 .remove = __devexit_p(msm_ocmem_remove),
880 .driver = {
881 .name = "msm_ocmem",
882 .owner = THIS_MODULE,
883 .of_match_table = msm_ocmem_dt_match,
884 },
885};
886
887static int __init ocmem_init(void)
888{
889 return platform_driver_register(&msm_ocmem_driver);
890}
891subsys_initcall(ocmem_init);
892
893static void __exit ocmem_exit(void)
894{
895 platform_driver_unregister(&msm_ocmem_driver);
896}
897module_exit(ocmem_exit);
898
899MODULE_LICENSE("GPL v2");
900MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");