blob: 793fcc558b9b4796d6288827217cd5cba7c0340d [file] [log] [blame]
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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",
85};
86
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070087struct ocmem_quota_table {
88 const char *name;
89 int id;
90 unsigned long start;
91 unsigned long size;
92 unsigned long min;
Naveen Ramaraj135cd672012-04-23 12:13:28 -070093 unsigned int tail;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -070094};
95
96/* This static table will go away with device tree support */
97static struct ocmem_quota_table qt[OCMEM_CLIENT_MAX] = {
Naveen Ramaraj135cd672012-04-23 12:13:28 -070098 /* name, id, start, size, min, tail */
99 { "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000, 0},
100 { "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000, 1},
101 { "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0, 0},
102 { "voice", OCMEM_VOICE, 0x0, 0x0, 0x0, 0 },
103 { "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0, 0},
104 { "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000, 0},
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700105 { "other_os", OCMEM_OTHER_OS, 0x120000, 0x20000, 0x20000, 0},
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700106 { "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000, 0},
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700107};
108
109static inline int get_id(const char *name)
110{
111 int i = 0;
112 for (i = 0 ; i < OCMEM_CLIENT_MAX; i++) {
113 if (strncmp(name, client_names[i], CLIENT_NAME_MAX) == 0)
114 return i;
115 }
116 return -EINVAL;
117}
118
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700119int check_id(int id)
120{
121 return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
122}
123
124const char *get_name(int id)
125{
126 if (!check_id(id))
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700127 return "Unknown";
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700128 return client_names[id];
129}
130
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700131inline unsigned long phys_to_offset(unsigned long addr)
132{
133 if (!ocmem_pdata)
134 return 0;
135 if (addr < ocmem_pdata->base ||
136 addr > (ocmem_pdata->base + ocmem_pdata->size))
137 return 0;
138 return addr - ocmem_pdata->base;
139}
140
141inline unsigned long offset_to_phys(unsigned long offset)
142{
143 if (!ocmem_pdata)
144 return 0;
145 if (offset > ocmem_pdata->size)
146 return 0;
147 return offset + ocmem_pdata->base;
148}
149
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700150inline int zone_active(int id)
151{
152 struct ocmem_zone *z = get_zone(id);
153 if (z)
154 return z->active == true ? 1 : 0;
155 else
156 return 0;
157}
158
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700159inline void inc_ocmem_stat(struct ocmem_zone *z,
160 enum ocmem_zstat_item item)
161{
162 if (!z)
163 return;
164 atomic_long_inc(&z->z_stat[item]);
165}
166
167inline unsigned long get_ocmem_stat(struct ocmem_zone *z,
168 enum ocmem_zstat_item item)
169{
170 if (!z)
171 return 0;
172 else
173 return atomic_long_read(&z->z_stat[item]);
174}
175
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700176static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
177{
178 struct ocmem_plat_data *pdata = NULL;
179 struct ocmem_partition *parts = NULL;
180 struct device *dev = &pdev->dev;
Naveen Ramaraje653c2b2012-05-30 12:59:25 -0700181 unsigned nr_parts = 0;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700182 int i;
183 int j;
184
185 pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
186 GFP_KERNEL);
187
188 if (!pdata) {
189 dev_err(dev, "Unable to allocate memory for"
190 " platform data\n");
191 return NULL;
192 }
193
194 for (i = 0 ; i < ARRAY_SIZE(qt); i++)
195 if (qt[i].size != 0x0)
196 nr_parts++;
197
198 if (nr_parts == 0x0) {
199 dev_err(dev, "No valid ocmem partitions\n");
200 return NULL;
201 } else
202 dev_info(dev, "Total partitions = %d\n", nr_parts);
203
204 parts = devm_kzalloc(dev, sizeof(struct ocmem_partition) * nr_parts,
205 GFP_KERNEL);
206
207 if (!parts) {
208 dev_err(dev, "Unable to allocate memory for"
209 " partition data\n");
210 return NULL;
211 }
212
213 for (i = 0, j = 0; i < ARRAY_SIZE(qt); i++) {
214 if (qt[i].size == 0x0) {
215 dev_dbg(dev, "Skipping creation of pool for %s\n",
216 qt[i].name);
217 continue;
218 }
219 parts[j].id = qt[i].id;
220 parts[j].p_size = qt[i].size;
221 parts[j].p_start = qt[i].start;
222 parts[j].p_min = qt[i].min;
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700223 parts[j].p_tail = qt[i].tail;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700224 j++;
225 }
226 BUG_ON(j != nr_parts);
227 pdata->nr_parts = nr_parts;
228 pdata->parts = parts;
229 pdata->base = OCMEM_PHYS_BASE;
230 pdata->size = OCMEM_PHYS_SIZE;
231 return pdata;
232}
233
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700234int __devinit of_ocmem_parse_regions(struct device *dev,
235 struct ocmem_partition **part)
236{
237 const char *name;
238 struct device_node *child = NULL;
239 int nr_parts = 0;
240 int i = 0;
241 int rc = 0;
242 int id = -1;
243
244 /*Compute total partitions */
245 for_each_child_of_node(dev->of_node, child)
246 nr_parts++;
247
248 if (nr_parts == 0)
249 return 0;
250
251 *part = devm_kzalloc(dev, nr_parts * sizeof(**part),
252 GFP_KERNEL);
253
254 if (!*part)
255 return -ENOMEM;
256
257 for_each_child_of_node(dev->of_node, child)
258 {
259 const u32 *addr;
260 u32 min;
261 u64 size;
262 u64 p_start;
263
264 addr = of_get_address(child, 0, &size, NULL);
265
266 if (!addr) {
267 dev_err(dev, "Invalid addr for partition %d, ignored\n",
268 i);
269 continue;
270 }
271
272 rc = of_property_read_u32(child, "qcom,ocmem-part-min", &min);
273
274 if (rc) {
275 dev_err(dev, "No min for partition %d, ignored\n", i);
276 continue;
277 }
278
279 rc = of_property_read_string(child, "qcom,ocmem-part-name",
280 &name);
281
282 if (rc) {
283 dev_err(dev, "No name for partition %d, ignored\n", i);
284 continue;
285 }
286
287 id = get_id(name);
288
289 if (id < 0) {
290 dev_err(dev, "Ignoring invalid partition %s\n", name);
291 continue;
292 }
293
294 p_start = of_translate_address(child, addr);
295
296 if (p_start == OF_BAD_ADDR) {
297 dev_err(dev, "Invalid offset for partition %d\n", i);
298 continue;
299 }
300
301 (*part)[i].p_start = p_start;
302 (*part)[i].p_size = size;
303 (*part)[i].id = id;
304 (*part)[i].name = name;
305 (*part)[i].p_min = min;
306 (*part)[i].p_tail = of_property_read_bool(child, "tail");
307 i++;
308 }
309
310 return i;
311}
312
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700313#if defined(CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL)
314static int parse_power_ctrl_config(struct ocmem_plat_data *pdata,
315 struct device_node *node)
316{
317 pdata->rpm_pwr_ctrl = false;
318 pdata->rpm_rsc_type = ~0x0;
319 return 0;
320}
321#else
322static int parse_power_ctrl_config(struct ocmem_plat_data *pdata,
323 struct device_node *node)
324{
325 unsigned rsc_type = ~0x0;
326 pdata->rpm_pwr_ctrl = false;
327 if (of_property_read_u32(node, "qcom,resource-type",
328 &rsc_type))
329 return -EINVAL;
330 pdata->rpm_pwr_ctrl = true;
331 pdata->rpm_rsc_type = rsc_type;
332 return 0;
333
334}
335#endif /* CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL */
336
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700337/* Core Clock Operations */
338int ocmem_enable_core_clock(void)
339{
340 int ret;
341 ret = clk_prepare_enable(ocmem_pdata->core_clk);
342 if (ret) {
343 pr_err("ocmem: Failed to enable core clock\n");
344 return ret;
345 }
346 pr_debug("ocmem: Enabled core clock\n");
347 return 0;
348}
349
350void ocmem_disable_core_clock(void)
351{
352 clk_disable_unprepare(ocmem_pdata->core_clk);
353 pr_debug("ocmem: Disabled core clock\n");
354}
355
356/* Branch Clock Operations */
357int ocmem_enable_iface_clock(void)
358{
359 int ret;
360 ret = clk_prepare_enable(ocmem_pdata->iface_clk);
361 if (ret) {
362 pr_err("ocmem: Failed to disable branch clock\n");
363 return ret;
364 }
365 pr_debug("ocmem: Enabled iface clock\n");
366 return 0;
367}
368
369void ocmem_disable_iface_clock(void)
370{
371 clk_disable_unprepare(ocmem_pdata->iface_clk);
372 pr_debug("ocmem: Disabled iface clock\n");
373}
374
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700375/* Block-Remapper Clock Operations */
376int ocmem_enable_br_clock(void)
377{
378 int ret;
379
380 ret = clk_prepare_enable(ocmem_pdata->br_clk);
381
382 if (ret) {
383 pr_err("ocmem: Failed to enable br clock\n");
384 return ret;
385 }
386 pr_debug("ocmem: Enabled br clock\n");
387 return 0;
388}
389
390void ocmem_disable_br_clock(void)
391{
392 clk_disable_unprepare(ocmem_pdata->br_clk);
393 pr_debug("ocmem: Disabled br clock\n");
394}
395
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700396static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
397{
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700398 struct device *dev = &pdev->dev;
399 struct device_node *node = pdev->dev.of_node;
400 struct ocmem_plat_data *pdata = NULL;
401 struct ocmem_partition *parts = NULL;
402 struct resource *ocmem_irq;
403 struct resource *dm_irq;
404 struct resource *ocmem_mem;
405 struct resource *reg_base;
406 struct resource *br_base;
407 struct resource *dm_base;
408 struct resource *ocmem_mem_io;
409 unsigned nr_parts = 0;
410 unsigned nr_regions = 0;
411
412 pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
413 GFP_KERNEL);
414
415 if (!pdata) {
416 dev_err(dev, "Unable to allocate memory for platform data\n");
417 return NULL;
418 }
419
420 ocmem_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
421 "ocmem_physical");
422 if (!ocmem_mem) {
423 dev_err(dev, "No OCMEM memory resource\n");
424 return NULL;
425 }
426
427 ocmem_mem_io = request_mem_region(ocmem_mem->start,
428 resource_size(ocmem_mem), pdev->name);
429
430 if (!ocmem_mem_io) {
431 dev_err(dev, "Could not claim OCMEM memory\n");
432 return NULL;
433 }
434
435 pdata->base = ocmem_mem->start;
436 pdata->size = resource_size(ocmem_mem);
437 pdata->vbase = devm_ioremap_nocache(dev, ocmem_mem->start,
438 resource_size(ocmem_mem));
439 if (!pdata->vbase) {
440 dev_err(dev, "Could not ioremap ocmem memory\n");
441 return NULL;
442 }
443
444 reg_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
445 "ocmem_ctrl_physical");
446 if (!reg_base) {
447 dev_err(dev, "No OCMEM register resource\n");
448 return NULL;
449 }
450
451 pdata->reg_base = devm_ioremap_nocache(dev, reg_base->start,
452 resource_size(reg_base));
453 if (!pdata->reg_base) {
454 dev_err(dev, "Could not ioremap register map\n");
455 return NULL;
456 }
457
458 br_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
459 "br_ctrl_physical");
460 if (!br_base) {
461 dev_err(dev, "No OCMEM BR resource\n");
462 return NULL;
463 }
464
465 pdata->br_base = devm_ioremap_nocache(dev, br_base->start,
466 resource_size(br_base));
467 if (!pdata->br_base) {
468 dev_err(dev, "Could not ioremap BR resource\n");
469 return NULL;
470 }
471
472 dm_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
473 "dm_ctrl_physical");
474 if (!dm_base) {
475 dev_err(dev, "No OCMEM DM resource\n");
476 return NULL;
477 }
478
479 pdata->dm_base = devm_ioremap_nocache(dev, dm_base->start,
480 resource_size(dm_base));
481 if (!pdata->dm_base) {
482 dev_err(dev, "Could not ioremap DM resource\n");
483 return NULL;
484 }
485
486 ocmem_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
487 "ocmem_irq");
488
489 if (!ocmem_irq) {
490 dev_err(dev, "No OCMEM IRQ resource\n");
491 return NULL;
492 }
493
494 dm_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
495 "dm_irq");
496
497 if (!dm_irq) {
498 dev_err(dev, "No DM IRQ resource\n");
499 return NULL;
500 }
501
502 if (of_property_read_u32(node, "qcom,ocmem-num-regions",
503 &nr_regions)) {
504 dev_err(dev, "No OCMEM memory regions specified\n");
505 }
506
507 if (nr_regions == 0) {
508 dev_err(dev, "No hardware memory regions found\n");
509 return NULL;
510 }
511
512 /* 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;
528 pdata->ocmem_irq = ocmem_irq->start;
529 pdata->dm_irq = dm_irq->start;
530 return pdata;
531pdata_error:
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700532 return NULL;
533}
534
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700535static int ocmem_zones_show(struct seq_file *f, void *dummy)
536{
537 unsigned i = 0;
538 for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
539 struct ocmem_zone *z = get_zone(i);
540 if (z && z->active == true)
541 seq_printf(f, "zone %s\t:0x%08lx - 0x%08lx (%4ld KB)\n",
542 get_name(z->owner), z->z_start, z->z_end - 1,
543 (z->z_end - z->z_start)/SZ_1K);
544 }
545 return 0;
546}
547
548static int ocmem_zones_open(struct inode *inode, struct file *file)
549{
550 return single_open(file, ocmem_zones_show, inode->i_private);
551}
552
553static const struct file_operations zones_show_fops = {
554 .open = ocmem_zones_open,
555 .read = seq_read,
556 .llseek = seq_lseek,
557 .release = seq_release,
558};
559
560static int ocmem_stats_show(struct seq_file *f, void *dummy)
561{
562 unsigned i = 0;
563 unsigned j = 0;
564 for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
565 struct ocmem_zone *z = get_zone(i);
566 if (z && z->active == true) {
567 seq_printf(f, "zone %s:\n", get_name(z->owner));
568 for (j = 0 ; j < ARRAY_SIZE(zstat_names); j++) {
569 seq_printf(f, "\t %s: %lu\n", zstat_names[j],
570 get_ocmem_stat(z, j));
571 }
572 }
573 }
574 return 0;
575}
576
577static int ocmem_stats_open(struct inode *inode, struct file *file)
578{
579 return single_open(file, ocmem_stats_show, inode->i_private);
580}
581
582static const struct file_operations stats_show_fops = {
583 .open = ocmem_stats_open,
584 .read = seq_read,
585 .llseek = seq_lseek,
586 .release = seq_release,
587};
588
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700589static int ocmem_zone_init(struct platform_device *pdev)
590{
591
592 int ret = -1;
593 int i = 0;
594 unsigned active_zones = 0;
595
596 struct ocmem_zone *zone = NULL;
597 struct ocmem_zone_ops *z_ops = NULL;
598 struct device *dev = &pdev->dev;
599 unsigned long start;
600 struct ocmem_plat_data *pdata = NULL;
601
602 pdata = platform_get_drvdata(pdev);
603
604 for (i = 0; i < pdata->nr_parts; i++) {
605 struct ocmem_partition *part = &pdata->parts[i];
606 zone = get_zone(part->id);
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700607 zone->active = false;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700608
609 dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
610 i, part->p_start, part->p_size,
611 client_names[part->id]);
612
613 if (part->p_size > pdata->size) {
614 dev_alert(dev, "Quota > ocmem_size for id:%d\n",
615 part->id);
616 continue;
617 }
618
619 zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
620
621 if (!zone->z_pool) {
622 dev_alert(dev, "Creating pool failed for id:%d\n",
623 part->id);
624 return -EBUSY;
625 }
626
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700627 start = part->p_start;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700628 ret = gen_pool_add(zone->z_pool, start,
629 part->p_size, -1);
630
631 if (ret < 0) {
632 gen_pool_destroy(zone->z_pool);
633 dev_alert(dev, "Unable to back pool %d with "
634 "buffer:%lx\n", part->id, part->p_size);
635 return -EBUSY;
636 }
637
638 /* Initialize zone allocators */
639 z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
640 GFP_KERNEL);
641 if (!z_ops) {
642 pr_alert("ocmem: Unable to allocate memory for"
643 "zone ops:%d\n", i);
644 return -EBUSY;
645 }
646
647 /* Initialize zone parameters */
648 zone->z_start = start;
649 zone->z_head = zone->z_start;
650 zone->z_end = start + part->p_size;
651 zone->z_tail = zone->z_end;
652 zone->z_free = part->p_size;
653 zone->owner = part->id;
654 zone->active_regions = 0;
655 zone->max_regions = 0;
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700656 INIT_LIST_HEAD(&zone->req_list);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700657 zone->z_ops = z_ops;
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700658 if (part->p_tail) {
659 z_ops->allocate = allocate_tail;
660 z_ops->free = free_tail;
661 } else {
662 z_ops->allocate = allocate_head;
663 z_ops->free = free_head;
664 }
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700665 /* zap the counters */
666 memset(zone->z_stat, 0 , sizeof(zone->z_stat));
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700667 zone->active = true;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700668 active_zones++;
669
670 if (active_zones == 1)
671 pr_info("Physical OCMEM zone layout:\n");
672
673 pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
674 client_names[part->id], zone->z_start,
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700675 zone->z_end - 1, part->p_size/SZ_1K);
676 }
677
678 if (!debugfs_create_file("zones", S_IRUGO, pdata->debug_node,
679 NULL, &zones_show_fops)) {
680 dev_err(dev, "Unable to create debugfs node for zones\n");
681 return -EBUSY;
682 }
683
684 if (!debugfs_create_file("stats", S_IRUGO, pdata->debug_node,
685 NULL, &stats_show_fops)) {
686 dev_err(dev, "Unable to create debugfs node for stats\n");
687 return -EBUSY;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700688 }
689
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700690 dev_dbg(dev, "Total active zones = %d\n", active_zones);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700691 return 0;
692}
693
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700694/* Enable the ocmem graphics mpU as a workaround */
695/* This will be programmed by TZ after TZ support is integrated */
696static int ocmem_init_gfx_mpu(struct platform_device *pdev)
697{
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700698 int rc;
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700699 struct device *dev = &pdev->dev;
700 void __iomem *ocmem_region_vbase = NULL;
701
702 ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
703 OCMEM_REGION_CTL_SIZE);
704 if (!ocmem_region_vbase)
705 return -EBUSY;
706
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700707 rc = ocmem_enable_core_clock();
708
709 if (rc < 0)
710 return rc;
711
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700712 writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700713 ocmem_disable_core_clock();
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700714 return 0;
715}
716
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700717static int __devinit ocmem_debugfs_init(struct platform_device *pdev)
718{
719 struct dentry *debug_dir = NULL;
720 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
721
722 debug_dir = debugfs_create_dir("ocmem", NULL);
723 if (!debug_dir || IS_ERR(debug_dir)) {
724 pr_err("ocmem: Unable to create debugfs root\n");
725 return PTR_ERR(debug_dir);
726 }
727
728 pdata->debug_node = debug_dir;
729 return 0;
730}
731
732static void __devexit ocmem_debugfs_exit(struct platform_device *pdev)
733{
734 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
735 debugfs_remove_recursive(pdata->debug_node);
736}
737
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700738static int __devinit msm_ocmem_probe(struct platform_device *pdev)
739{
740 struct device *dev = &pdev->dev;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700741 struct clk *ocmem_core_clk = NULL;
742 struct clk *ocmem_iface_clk = NULL;
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700743 struct clk *ocmem_br_clk = NULL;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700744
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700745 if (!pdev->dev.of_node) {
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700746 dev_info(dev, "Missing Configuration in Device Tree\n");
747 ocmem_pdata = parse_static_config(pdev);
748 } else {
749 ocmem_pdata = parse_dt_config(pdev);
750 }
751
752 /* Check if we have some configuration data to start */
753 if (!ocmem_pdata)
754 return -ENODEV;
755
756 /* Sanity Checks */
757 BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
758 BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
759
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700760 dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
761
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700762 ocmem_core_clk = devm_clk_get(dev, "core_clk");
763
764 if (IS_ERR(ocmem_core_clk)) {
765 dev_err(dev, "Unable to get the core clock\n");
766 return PTR_ERR(ocmem_core_clk);
767 }
768
769 /* The core clock is synchronous with graphics */
770 if (clk_set_rate(ocmem_core_clk, 1000) < 0) {
771 dev_err(dev, "Set rate failed on the core clock\n");
772 return -EBUSY;
773 }
774
775 ocmem_iface_clk = devm_clk_get(dev, "iface_clk");
776
777 if (IS_ERR(ocmem_iface_clk)) {
778 dev_err(dev, "Unable to get the memory interface clock\n");
779 return PTR_ERR(ocmem_core_clk);
780 };
781
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700782 ocmem_br_clk = devm_clk_get(dev, "br_clk");
783
784 if (IS_ERR(ocmem_br_clk)) {
785 dev_err(dev, "Unable to get the BR clock\n");
786 return PTR_ERR(ocmem_br_clk);
787 }
788
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700789 ocmem_pdata->core_clk = ocmem_core_clk;
790 ocmem_pdata->iface_clk = ocmem_iface_clk;
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700791 ocmem_pdata->br_clk = ocmem_br_clk;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700792
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700793 platform_set_drvdata(pdev, ocmem_pdata);
794
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700795 if (ocmem_debugfs_init(pdev))
796 return -EBUSY;
797
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700798 if (ocmem_core_init(pdev))
799 return -EBUSY;
800
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700801 if (ocmem_zone_init(pdev))
802 return -EBUSY;
803
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -0700804 if (ocmem_notifier_init())
805 return -EBUSY;
806
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700807 if (ocmem_sched_init(pdev))
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700808 return -EBUSY;
Naveen Ramaraj5b0982b2012-06-20 23:02:33 -0700809
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700810 if (ocmem_rdm_init(pdev))
811 return -EBUSY;
812
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700813 if (ocmem_init_gfx_mpu(pdev)) {
814 dev_err(dev, "Unable to initialize Graphics mPU\n");
815 return -EBUSY;
816 }
817
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700818 dev_dbg(dev, "initialized successfully\n");
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700819 return 0;
820}
821
822static int __devexit msm_ocmem_remove(struct platform_device *pdev)
823{
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700824 ocmem_debugfs_exit(pdev);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700825 return 0;
826}
827
828static struct of_device_id msm_ocmem_dt_match[] = {
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700829 { .compatible = "qcom,msm-ocmem",
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700830 },
831 {}
832};
833
834static struct platform_driver msm_ocmem_driver = {
835 .probe = msm_ocmem_probe,
836 .remove = __devexit_p(msm_ocmem_remove),
837 .driver = {
838 .name = "msm_ocmem",
839 .owner = THIS_MODULE,
840 .of_match_table = msm_ocmem_dt_match,
841 },
842};
843
844static int __init ocmem_init(void)
845{
846 return platform_driver_register(&msm_ocmem_driver);
847}
848subsys_initcall(ocmem_init);
849
850static void __exit ocmem_exit(void)
851{
852 platform_driver_unregister(&msm_ocmem_driver);
853}
854module_exit(ocmem_exit);
855
856MODULE_LICENSE("GPL v2");
857MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");