blob: 34fd8d2a6211144fd2044ab27f1694b5002506c7 [file] [log] [blame]
Neeti Desaiff663962012-11-20 15:32:13 -08001/* Copyright (c) 2012, 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;
362 ret = clk_prepare_enable(ocmem_pdata->iface_clk);
363 if (ret) {
364 pr_err("ocmem: Failed to disable branch clock\n");
365 return ret;
366 }
367 pr_debug("ocmem: Enabled iface clock\n");
368 return 0;
369}
370
371void ocmem_disable_iface_clock(void)
372{
373 clk_disable_unprepare(ocmem_pdata->iface_clk);
374 pr_debug("ocmem: Disabled iface clock\n");
375}
376
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700377/* Block-Remapper Clock Operations */
378int ocmem_enable_br_clock(void)
379{
380 int ret;
381
382 ret = clk_prepare_enable(ocmem_pdata->br_clk);
383
384 if (ret) {
385 pr_err("ocmem: Failed to enable br clock\n");
386 return ret;
387 }
388 pr_debug("ocmem: Enabled br clock\n");
389 return 0;
390}
391
392void ocmem_disable_br_clock(void)
393{
394 clk_disable_unprepare(ocmem_pdata->br_clk);
395 pr_debug("ocmem: Disabled br clock\n");
396}
397
Neeti Desaiff663962012-11-20 15:32:13 -0800398static struct ocmem_plat_data * __devinit parse_dt_config
399 (struct platform_device *pdev)
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700400{
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700401 struct device *dev = &pdev->dev;
402 struct device_node *node = pdev->dev.of_node;
403 struct ocmem_plat_data *pdata = NULL;
404 struct ocmem_partition *parts = NULL;
405 struct resource *ocmem_irq;
406 struct resource *dm_irq;
407 struct resource *ocmem_mem;
408 struct resource *reg_base;
409 struct resource *br_base;
410 struct resource *dm_base;
411 struct resource *ocmem_mem_io;
412 unsigned nr_parts = 0;
413 unsigned nr_regions = 0;
414
415 pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
416 GFP_KERNEL);
417
418 if (!pdata) {
419 dev_err(dev, "Unable to allocate memory for platform data\n");
420 return NULL;
421 }
422
423 ocmem_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
424 "ocmem_physical");
425 if (!ocmem_mem) {
426 dev_err(dev, "No OCMEM memory resource\n");
427 return NULL;
428 }
429
430 ocmem_mem_io = request_mem_region(ocmem_mem->start,
431 resource_size(ocmem_mem), pdev->name);
432
433 if (!ocmem_mem_io) {
434 dev_err(dev, "Could not claim OCMEM memory\n");
435 return NULL;
436 }
437
438 pdata->base = ocmem_mem->start;
439 pdata->size = resource_size(ocmem_mem);
440 pdata->vbase = devm_ioremap_nocache(dev, ocmem_mem->start,
441 resource_size(ocmem_mem));
442 if (!pdata->vbase) {
443 dev_err(dev, "Could not ioremap ocmem memory\n");
444 return NULL;
445 }
446
447 reg_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
448 "ocmem_ctrl_physical");
449 if (!reg_base) {
450 dev_err(dev, "No OCMEM register resource\n");
451 return NULL;
452 }
453
454 pdata->reg_base = devm_ioremap_nocache(dev, reg_base->start,
455 resource_size(reg_base));
456 if (!pdata->reg_base) {
457 dev_err(dev, "Could not ioremap register map\n");
458 return NULL;
459 }
460
461 br_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
462 "br_ctrl_physical");
463 if (!br_base) {
464 dev_err(dev, "No OCMEM BR resource\n");
465 return NULL;
466 }
467
468 pdata->br_base = devm_ioremap_nocache(dev, br_base->start,
469 resource_size(br_base));
470 if (!pdata->br_base) {
471 dev_err(dev, "Could not ioremap BR resource\n");
472 return NULL;
473 }
474
475 dm_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
476 "dm_ctrl_physical");
477 if (!dm_base) {
478 dev_err(dev, "No OCMEM DM resource\n");
479 return NULL;
480 }
481
482 pdata->dm_base = devm_ioremap_nocache(dev, dm_base->start,
483 resource_size(dm_base));
484 if (!pdata->dm_base) {
485 dev_err(dev, "Could not ioremap DM resource\n");
486 return NULL;
487 }
488
489 ocmem_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
490 "ocmem_irq");
491
492 if (!ocmem_irq) {
493 dev_err(dev, "No OCMEM IRQ resource\n");
494 return NULL;
495 }
496
497 dm_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
498 "dm_irq");
499
500 if (!dm_irq) {
501 dev_err(dev, "No DM IRQ resource\n");
502 return NULL;
503 }
504
505 if (of_property_read_u32(node, "qcom,ocmem-num-regions",
506 &nr_regions)) {
507 dev_err(dev, "No OCMEM memory regions specified\n");
508 }
509
510 if (nr_regions == 0) {
511 dev_err(dev, "No hardware memory regions found\n");
512 return NULL;
513 }
514
515 /* Figure out the number of partititons */
516 nr_parts = of_ocmem_parse_regions(dev, &parts);
517 if (nr_parts <= 0) {
518 dev_err(dev, "No valid OCMEM partitions found\n");
519 goto pdata_error;
520 } else
521 dev_dbg(dev, "Found %d ocmem partitions\n", nr_parts);
522
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700523 if (parse_power_ctrl_config(pdata, node)) {
524 dev_err(dev, "No OCMEM RPM Resource specified\n");
525 return NULL;
526 }
527
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700528 pdata->nr_parts = nr_parts;
529 pdata->parts = parts;
530 pdata->nr_regions = nr_regions;
531 pdata->ocmem_irq = ocmem_irq->start;
532 pdata->dm_irq = dm_irq->start;
533 return pdata;
534pdata_error:
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700535 return NULL;
536}
537
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700538static int ocmem_zones_show(struct seq_file *f, void *dummy)
539{
540 unsigned i = 0;
541 for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
542 struct ocmem_zone *z = get_zone(i);
543 if (z && z->active == true)
544 seq_printf(f, "zone %s\t:0x%08lx - 0x%08lx (%4ld KB)\n",
545 get_name(z->owner), z->z_start, z->z_end - 1,
546 (z->z_end - z->z_start)/SZ_1K);
547 }
548 return 0;
549}
550
551static int ocmem_zones_open(struct inode *inode, struct file *file)
552{
553 return single_open(file, ocmem_zones_show, inode->i_private);
554}
555
556static const struct file_operations zones_show_fops = {
557 .open = ocmem_zones_open,
558 .read = seq_read,
559 .llseek = seq_lseek,
560 .release = seq_release,
561};
562
563static int ocmem_stats_show(struct seq_file *f, void *dummy)
564{
565 unsigned i = 0;
566 unsigned j = 0;
567 for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
568 struct ocmem_zone *z = get_zone(i);
569 if (z && z->active == true) {
570 seq_printf(f, "zone %s:\n", get_name(z->owner));
571 for (j = 0 ; j < ARRAY_SIZE(zstat_names); j++) {
572 seq_printf(f, "\t %s: %lu\n", zstat_names[j],
573 get_ocmem_stat(z, j));
574 }
575 }
576 }
577 return 0;
578}
579
580static int ocmem_stats_open(struct inode *inode, struct file *file)
581{
582 return single_open(file, ocmem_stats_show, inode->i_private);
583}
584
585static const struct file_operations stats_show_fops = {
586 .open = ocmem_stats_open,
587 .read = seq_read,
588 .llseek = seq_lseek,
589 .release = seq_release,
590};
591
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700592static int ocmem_zone_init(struct platform_device *pdev)
593{
594
595 int ret = -1;
596 int i = 0;
597 unsigned active_zones = 0;
598
599 struct ocmem_zone *zone = NULL;
600 struct ocmem_zone_ops *z_ops = NULL;
601 struct device *dev = &pdev->dev;
602 unsigned long start;
603 struct ocmem_plat_data *pdata = NULL;
604
605 pdata = platform_get_drvdata(pdev);
606
607 for (i = 0; i < pdata->nr_parts; i++) {
608 struct ocmem_partition *part = &pdata->parts[i];
609 zone = get_zone(part->id);
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700610 zone->active = false;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700611
612 dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
613 i, part->p_start, part->p_size,
614 client_names[part->id]);
615
616 if (part->p_size > pdata->size) {
617 dev_alert(dev, "Quota > ocmem_size for id:%d\n",
618 part->id);
619 continue;
620 }
621
622 zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
623
624 if (!zone->z_pool) {
625 dev_alert(dev, "Creating pool failed for id:%d\n",
626 part->id);
627 return -EBUSY;
628 }
629
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700630 start = part->p_start;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700631 ret = gen_pool_add(zone->z_pool, start,
632 part->p_size, -1);
633
634 if (ret < 0) {
635 gen_pool_destroy(zone->z_pool);
636 dev_alert(dev, "Unable to back pool %d with "
637 "buffer:%lx\n", part->id, part->p_size);
638 return -EBUSY;
639 }
640
641 /* Initialize zone allocators */
642 z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
643 GFP_KERNEL);
644 if (!z_ops) {
645 pr_alert("ocmem: Unable to allocate memory for"
646 "zone ops:%d\n", i);
647 return -EBUSY;
648 }
649
650 /* Initialize zone parameters */
651 zone->z_start = start;
652 zone->z_head = zone->z_start;
653 zone->z_end = start + part->p_size;
654 zone->z_tail = zone->z_end;
655 zone->z_free = part->p_size;
656 zone->owner = part->id;
657 zone->active_regions = 0;
658 zone->max_regions = 0;
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700659 INIT_LIST_HEAD(&zone->req_list);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700660 zone->z_ops = z_ops;
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700661 if (part->p_tail) {
662 z_ops->allocate = allocate_tail;
663 z_ops->free = free_tail;
664 } else {
665 z_ops->allocate = allocate_head;
666 z_ops->free = free_head;
667 }
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700668 /* zap the counters */
669 memset(zone->z_stat, 0 , sizeof(zone->z_stat));
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700670 zone->active = true;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700671 active_zones++;
672
673 if (active_zones == 1)
674 pr_info("Physical OCMEM zone layout:\n");
675
676 pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
677 client_names[part->id], zone->z_start,
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700678 zone->z_end - 1, part->p_size/SZ_1K);
679 }
680
681 if (!debugfs_create_file("zones", S_IRUGO, pdata->debug_node,
682 NULL, &zones_show_fops)) {
683 dev_err(dev, "Unable to create debugfs node for zones\n");
684 return -EBUSY;
685 }
686
687 if (!debugfs_create_file("stats", S_IRUGO, pdata->debug_node,
688 NULL, &stats_show_fops)) {
689 dev_err(dev, "Unable to create debugfs node for stats\n");
690 return -EBUSY;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700691 }
692
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700693 dev_dbg(dev, "Total active zones = %d\n", active_zones);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700694 return 0;
695}
696
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700697/* Enable the ocmem graphics mpU as a workaround */
698/* This will be programmed by TZ after TZ support is integrated */
699static int ocmem_init_gfx_mpu(struct platform_device *pdev)
700{
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700701 int rc;
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700702 struct device *dev = &pdev->dev;
703 void __iomem *ocmem_region_vbase = NULL;
704
705 ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
706 OCMEM_REGION_CTL_SIZE);
707 if (!ocmem_region_vbase)
708 return -EBUSY;
709
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700710 rc = ocmem_enable_core_clock();
711
712 if (rc < 0)
713 return rc;
714
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700715 writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700716 ocmem_disable_core_clock();
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700717 return 0;
718}
719
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700720static int __devinit ocmem_debugfs_init(struct platform_device *pdev)
721{
722 struct dentry *debug_dir = NULL;
723 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
724
725 debug_dir = debugfs_create_dir("ocmem", NULL);
726 if (!debug_dir || IS_ERR(debug_dir)) {
727 pr_err("ocmem: Unable to create debugfs root\n");
728 return PTR_ERR(debug_dir);
729 }
730
731 pdata->debug_node = debug_dir;
732 return 0;
733}
734
735static void __devexit ocmem_debugfs_exit(struct platform_device *pdev)
736{
737 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
738 debugfs_remove_recursive(pdata->debug_node);
739}
740
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700741static int __devinit msm_ocmem_probe(struct platform_device *pdev)
742{
743 struct device *dev = &pdev->dev;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700744 struct clk *ocmem_core_clk = NULL;
745 struct clk *ocmem_iface_clk = NULL;
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700746 struct clk *ocmem_br_clk = NULL;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700747
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700748 if (!pdev->dev.of_node) {
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700749 dev_info(dev, "Missing Configuration in Device Tree\n");
750 ocmem_pdata = parse_static_config(pdev);
751 } else {
752 ocmem_pdata = parse_dt_config(pdev);
753 }
754
755 /* Check if we have some configuration data to start */
756 if (!ocmem_pdata)
757 return -ENODEV;
758
759 /* Sanity Checks */
760 BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
761 BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
762
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700763 dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
764
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700765 ocmem_core_clk = devm_clk_get(dev, "core_clk");
766
767 if (IS_ERR(ocmem_core_clk)) {
768 dev_err(dev, "Unable to get the core clock\n");
769 return PTR_ERR(ocmem_core_clk);
770 }
771
772 /* The core clock is synchronous with graphics */
773 if (clk_set_rate(ocmem_core_clk, 1000) < 0) {
774 dev_err(dev, "Set rate failed on the core clock\n");
775 return -EBUSY;
776 }
777
778 ocmem_iface_clk = devm_clk_get(dev, "iface_clk");
779
780 if (IS_ERR(ocmem_iface_clk)) {
781 dev_err(dev, "Unable to get the memory interface clock\n");
782 return PTR_ERR(ocmem_core_clk);
783 };
784
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700785 ocmem_br_clk = devm_clk_get(dev, "br_clk");
786
787 if (IS_ERR(ocmem_br_clk)) {
788 dev_err(dev, "Unable to get the BR clock\n");
789 return PTR_ERR(ocmem_br_clk);
790 }
791
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700792 ocmem_pdata->core_clk = ocmem_core_clk;
793 ocmem_pdata->iface_clk = ocmem_iface_clk;
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700794 ocmem_pdata->br_clk = ocmem_br_clk;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700795
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700796 platform_set_drvdata(pdev, ocmem_pdata);
797
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700798 if (ocmem_debugfs_init(pdev))
799 return -EBUSY;
800
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700801 if (ocmem_core_init(pdev))
802 return -EBUSY;
803
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700804 if (ocmem_zone_init(pdev))
805 return -EBUSY;
806
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -0700807 if (ocmem_notifier_init())
808 return -EBUSY;
809
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700810 if (ocmem_sched_init(pdev))
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700811 return -EBUSY;
Naveen Ramaraj5b0982b2012-06-20 23:02:33 -0700812
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700813 if (ocmem_rdm_init(pdev))
814 return -EBUSY;
815
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700816 if (ocmem_init_gfx_mpu(pdev)) {
817 dev_err(dev, "Unable to initialize Graphics mPU\n");
818 return -EBUSY;
819 }
820
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700821 dev_dbg(dev, "initialized successfully\n");
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700822 return 0;
823}
824
825static int __devexit msm_ocmem_remove(struct platform_device *pdev)
826{
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700827 ocmem_debugfs_exit(pdev);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700828 return 0;
829}
830
831static struct of_device_id msm_ocmem_dt_match[] = {
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700832 { .compatible = "qcom,msm-ocmem",
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700833 },
834 {}
835};
836
837static struct platform_driver msm_ocmem_driver = {
838 .probe = msm_ocmem_probe,
839 .remove = __devexit_p(msm_ocmem_remove),
840 .driver = {
841 .name = "msm_ocmem",
842 .owner = THIS_MODULE,
843 .of_match_table = msm_ocmem_dt_match,
844 },
845};
846
847static int __init ocmem_init(void)
848{
849 return platform_driver_register(&msm_ocmem_driver);
850}
851subsys_initcall(ocmem_init);
852
853static void __exit ocmem_exit(void)
854{
855 platform_driver_unregister(&msm_ocmem_driver);
856}
857module_exit(ocmem_exit);
858
859MODULE_LICENSE("GPL v2");
860MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");