blob: 7829d8decfffa9e6973606e0012d4e314de82d0a [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",
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
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700398static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
399{
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700400 struct device *dev = &pdev->dev;
401 struct device_node *node = pdev->dev.of_node;
402 struct ocmem_plat_data *pdata = NULL;
403 struct ocmem_partition *parts = NULL;
404 struct resource *ocmem_irq;
405 struct resource *dm_irq;
406 struct resource *ocmem_mem;
407 struct resource *reg_base;
408 struct resource *br_base;
409 struct resource *dm_base;
410 struct resource *ocmem_mem_io;
411 unsigned nr_parts = 0;
412 unsigned nr_regions = 0;
413
414 pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
415 GFP_KERNEL);
416
417 if (!pdata) {
418 dev_err(dev, "Unable to allocate memory for platform data\n");
419 return NULL;
420 }
421
422 ocmem_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
423 "ocmem_physical");
424 if (!ocmem_mem) {
425 dev_err(dev, "No OCMEM memory resource\n");
426 return NULL;
427 }
428
429 ocmem_mem_io = request_mem_region(ocmem_mem->start,
430 resource_size(ocmem_mem), pdev->name);
431
432 if (!ocmem_mem_io) {
433 dev_err(dev, "Could not claim OCMEM memory\n");
434 return NULL;
435 }
436
437 pdata->base = ocmem_mem->start;
438 pdata->size = resource_size(ocmem_mem);
439 pdata->vbase = devm_ioremap_nocache(dev, ocmem_mem->start,
440 resource_size(ocmem_mem));
441 if (!pdata->vbase) {
442 dev_err(dev, "Could not ioremap ocmem memory\n");
443 return NULL;
444 }
445
446 reg_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
447 "ocmem_ctrl_physical");
448 if (!reg_base) {
449 dev_err(dev, "No OCMEM register resource\n");
450 return NULL;
451 }
452
453 pdata->reg_base = devm_ioremap_nocache(dev, reg_base->start,
454 resource_size(reg_base));
455 if (!pdata->reg_base) {
456 dev_err(dev, "Could not ioremap register map\n");
457 return NULL;
458 }
459
460 br_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
461 "br_ctrl_physical");
462 if (!br_base) {
463 dev_err(dev, "No OCMEM BR resource\n");
464 return NULL;
465 }
466
467 pdata->br_base = devm_ioremap_nocache(dev, br_base->start,
468 resource_size(br_base));
469 if (!pdata->br_base) {
470 dev_err(dev, "Could not ioremap BR resource\n");
471 return NULL;
472 }
473
474 dm_base = platform_get_resource_byname(pdev, IORESOURCE_MEM,
475 "dm_ctrl_physical");
476 if (!dm_base) {
477 dev_err(dev, "No OCMEM DM resource\n");
478 return NULL;
479 }
480
481 pdata->dm_base = devm_ioremap_nocache(dev, dm_base->start,
482 resource_size(dm_base));
483 if (!pdata->dm_base) {
484 dev_err(dev, "Could not ioremap DM resource\n");
485 return NULL;
486 }
487
488 ocmem_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
489 "ocmem_irq");
490
491 if (!ocmem_irq) {
492 dev_err(dev, "No OCMEM IRQ resource\n");
493 return NULL;
494 }
495
496 dm_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
497 "dm_irq");
498
499 if (!dm_irq) {
500 dev_err(dev, "No DM IRQ resource\n");
501 return NULL;
502 }
503
504 if (of_property_read_u32(node, "qcom,ocmem-num-regions",
505 &nr_regions)) {
506 dev_err(dev, "No OCMEM memory regions specified\n");
507 }
508
509 if (nr_regions == 0) {
510 dev_err(dev, "No hardware memory regions found\n");
511 return NULL;
512 }
513
514 /* Figure out the number of partititons */
515 nr_parts = of_ocmem_parse_regions(dev, &parts);
516 if (nr_parts <= 0) {
517 dev_err(dev, "No valid OCMEM partitions found\n");
518 goto pdata_error;
519 } else
520 dev_dbg(dev, "Found %d ocmem partitions\n", nr_parts);
521
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700522 if (parse_power_ctrl_config(pdata, node)) {
523 dev_err(dev, "No OCMEM RPM Resource specified\n");
524 return NULL;
525 }
526
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700527 pdata->nr_parts = nr_parts;
528 pdata->parts = parts;
529 pdata->nr_regions = nr_regions;
530 pdata->ocmem_irq = ocmem_irq->start;
531 pdata->dm_irq = dm_irq->start;
532 return pdata;
533pdata_error:
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700534 return NULL;
535}
536
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700537static int ocmem_zones_show(struct seq_file *f, void *dummy)
538{
539 unsigned i = 0;
540 for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
541 struct ocmem_zone *z = get_zone(i);
542 if (z && z->active == true)
543 seq_printf(f, "zone %s\t:0x%08lx - 0x%08lx (%4ld KB)\n",
544 get_name(z->owner), z->z_start, z->z_end - 1,
545 (z->z_end - z->z_start)/SZ_1K);
546 }
547 return 0;
548}
549
550static int ocmem_zones_open(struct inode *inode, struct file *file)
551{
552 return single_open(file, ocmem_zones_show, inode->i_private);
553}
554
555static const struct file_operations zones_show_fops = {
556 .open = ocmem_zones_open,
557 .read = seq_read,
558 .llseek = seq_lseek,
559 .release = seq_release,
560};
561
562static int ocmem_stats_show(struct seq_file *f, void *dummy)
563{
564 unsigned i = 0;
565 unsigned j = 0;
566 for (i = OCMEM_GRAPHICS; i < OCMEM_CLIENT_MAX; i++) {
567 struct ocmem_zone *z = get_zone(i);
568 if (z && z->active == true) {
569 seq_printf(f, "zone %s:\n", get_name(z->owner));
570 for (j = 0 ; j < ARRAY_SIZE(zstat_names); j++) {
571 seq_printf(f, "\t %s: %lu\n", zstat_names[j],
572 get_ocmem_stat(z, j));
573 }
574 }
575 }
576 return 0;
577}
578
579static int ocmem_stats_open(struct inode *inode, struct file *file)
580{
581 return single_open(file, ocmem_stats_show, inode->i_private);
582}
583
584static const struct file_operations stats_show_fops = {
585 .open = ocmem_stats_open,
586 .read = seq_read,
587 .llseek = seq_lseek,
588 .release = seq_release,
589};
590
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700591static int ocmem_zone_init(struct platform_device *pdev)
592{
593
594 int ret = -1;
595 int i = 0;
596 unsigned active_zones = 0;
597
598 struct ocmem_zone *zone = NULL;
599 struct ocmem_zone_ops *z_ops = NULL;
600 struct device *dev = &pdev->dev;
601 unsigned long start;
602 struct ocmem_plat_data *pdata = NULL;
603
604 pdata = platform_get_drvdata(pdev);
605
606 for (i = 0; i < pdata->nr_parts; i++) {
607 struct ocmem_partition *part = &pdata->parts[i];
608 zone = get_zone(part->id);
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700609 zone->active = false;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700610
611 dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
612 i, part->p_start, part->p_size,
613 client_names[part->id]);
614
615 if (part->p_size > pdata->size) {
616 dev_alert(dev, "Quota > ocmem_size for id:%d\n",
617 part->id);
618 continue;
619 }
620
621 zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
622
623 if (!zone->z_pool) {
624 dev_alert(dev, "Creating pool failed for id:%d\n",
625 part->id);
626 return -EBUSY;
627 }
628
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700629 start = part->p_start;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700630 ret = gen_pool_add(zone->z_pool, start,
631 part->p_size, -1);
632
633 if (ret < 0) {
634 gen_pool_destroy(zone->z_pool);
635 dev_alert(dev, "Unable to back pool %d with "
636 "buffer:%lx\n", part->id, part->p_size);
637 return -EBUSY;
638 }
639
640 /* Initialize zone allocators */
641 z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
642 GFP_KERNEL);
643 if (!z_ops) {
644 pr_alert("ocmem: Unable to allocate memory for"
645 "zone ops:%d\n", i);
646 return -EBUSY;
647 }
648
649 /* Initialize zone parameters */
650 zone->z_start = start;
651 zone->z_head = zone->z_start;
652 zone->z_end = start + part->p_size;
653 zone->z_tail = zone->z_end;
654 zone->z_free = part->p_size;
655 zone->owner = part->id;
656 zone->active_regions = 0;
657 zone->max_regions = 0;
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700658 INIT_LIST_HEAD(&zone->req_list);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700659 zone->z_ops = z_ops;
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700660 if (part->p_tail) {
661 z_ops->allocate = allocate_tail;
662 z_ops->free = free_tail;
663 } else {
664 z_ops->allocate = allocate_head;
665 z_ops->free = free_head;
666 }
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700667 /* zap the counters */
668 memset(zone->z_stat, 0 , sizeof(zone->z_stat));
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700669 zone->active = true;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700670 active_zones++;
671
672 if (active_zones == 1)
673 pr_info("Physical OCMEM zone layout:\n");
674
675 pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
676 client_names[part->id], zone->z_start,
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700677 zone->z_end - 1, part->p_size/SZ_1K);
678 }
679
680 if (!debugfs_create_file("zones", S_IRUGO, pdata->debug_node,
681 NULL, &zones_show_fops)) {
682 dev_err(dev, "Unable to create debugfs node for zones\n");
683 return -EBUSY;
684 }
685
686 if (!debugfs_create_file("stats", S_IRUGO, pdata->debug_node,
687 NULL, &stats_show_fops)) {
688 dev_err(dev, "Unable to create debugfs node for stats\n");
689 return -EBUSY;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700690 }
691
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700692 dev_dbg(dev, "Total active zones = %d\n", active_zones);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700693 return 0;
694}
695
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700696/* Enable the ocmem graphics mpU as a workaround */
697/* This will be programmed by TZ after TZ support is integrated */
698static int ocmem_init_gfx_mpu(struct platform_device *pdev)
699{
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700700 int rc;
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700701 struct device *dev = &pdev->dev;
702 void __iomem *ocmem_region_vbase = NULL;
703
704 ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
705 OCMEM_REGION_CTL_SIZE);
706 if (!ocmem_region_vbase)
707 return -EBUSY;
708
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700709 rc = ocmem_enable_core_clock();
710
711 if (rc < 0)
712 return rc;
713
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700714 writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700715 ocmem_disable_core_clock();
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700716 return 0;
717}
718
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700719static int __devinit ocmem_debugfs_init(struct platform_device *pdev)
720{
721 struct dentry *debug_dir = NULL;
722 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
723
724 debug_dir = debugfs_create_dir("ocmem", NULL);
725 if (!debug_dir || IS_ERR(debug_dir)) {
726 pr_err("ocmem: Unable to create debugfs root\n");
727 return PTR_ERR(debug_dir);
728 }
729
730 pdata->debug_node = debug_dir;
731 return 0;
732}
733
734static void __devexit ocmem_debugfs_exit(struct platform_device *pdev)
735{
736 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
737 debugfs_remove_recursive(pdata->debug_node);
738}
739
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700740static int __devinit msm_ocmem_probe(struct platform_device *pdev)
741{
742 struct device *dev = &pdev->dev;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700743 struct clk *ocmem_core_clk = NULL;
744 struct clk *ocmem_iface_clk = NULL;
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700745 struct clk *ocmem_br_clk = NULL;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700746
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700747 if (!pdev->dev.of_node) {
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700748 dev_info(dev, "Missing Configuration in Device Tree\n");
749 ocmem_pdata = parse_static_config(pdev);
750 } else {
751 ocmem_pdata = parse_dt_config(pdev);
752 }
753
754 /* Check if we have some configuration data to start */
755 if (!ocmem_pdata)
756 return -ENODEV;
757
758 /* Sanity Checks */
759 BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
760 BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
761
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700762 dev_info(dev, "OCMEM Virtual addr %p\n", ocmem_pdata->vbase);
763
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700764 ocmem_core_clk = devm_clk_get(dev, "core_clk");
765
766 if (IS_ERR(ocmem_core_clk)) {
767 dev_err(dev, "Unable to get the core clock\n");
768 return PTR_ERR(ocmem_core_clk);
769 }
770
771 /* The core clock is synchronous with graphics */
772 if (clk_set_rate(ocmem_core_clk, 1000) < 0) {
773 dev_err(dev, "Set rate failed on the core clock\n");
774 return -EBUSY;
775 }
776
777 ocmem_iface_clk = devm_clk_get(dev, "iface_clk");
778
779 if (IS_ERR(ocmem_iface_clk)) {
780 dev_err(dev, "Unable to get the memory interface clock\n");
781 return PTR_ERR(ocmem_core_clk);
782 };
783
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700784 ocmem_br_clk = devm_clk_get(dev, "br_clk");
785
786 if (IS_ERR(ocmem_br_clk)) {
787 dev_err(dev, "Unable to get the BR clock\n");
788 return PTR_ERR(ocmem_br_clk);
789 }
790
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700791 ocmem_pdata->core_clk = ocmem_core_clk;
792 ocmem_pdata->iface_clk = ocmem_iface_clk;
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700793 ocmem_pdata->br_clk = ocmem_br_clk;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700794
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700795 platform_set_drvdata(pdev, ocmem_pdata);
796
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700797 if (ocmem_debugfs_init(pdev))
798 return -EBUSY;
799
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700800 if (ocmem_core_init(pdev))
801 return -EBUSY;
802
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700803 if (ocmem_zone_init(pdev))
804 return -EBUSY;
805
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -0700806 if (ocmem_notifier_init())
807 return -EBUSY;
808
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700809 if (ocmem_sched_init(pdev))
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700810 return -EBUSY;
Naveen Ramaraj5b0982b2012-06-20 23:02:33 -0700811
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700812 if (ocmem_rdm_init(pdev))
813 return -EBUSY;
814
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700815 if (ocmem_init_gfx_mpu(pdev)) {
816 dev_err(dev, "Unable to initialize Graphics mPU\n");
817 return -EBUSY;
818 }
819
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700820 dev_dbg(dev, "initialized successfully\n");
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700821 return 0;
822}
823
824static int __devexit msm_ocmem_remove(struct platform_device *pdev)
825{
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700826 ocmem_debugfs_exit(pdev);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700827 return 0;
828}
829
830static struct of_device_id msm_ocmem_dt_match[] = {
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700831 { .compatible = "qcom,msm-ocmem",
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700832 },
833 {}
834};
835
836static struct platform_driver msm_ocmem_driver = {
837 .probe = msm_ocmem_probe,
838 .remove = __devexit_p(msm_ocmem_remove),
839 .driver = {
840 .name = "msm_ocmem",
841 .owner = THIS_MODULE,
842 .of_match_table = msm_ocmem_dt_match,
843 },
844};
845
846static int __init ocmem_init(void)
847{
848 return platform_driver_register(&msm_ocmem_driver);
849}
850subsys_initcall(ocmem_init);
851
852static void __exit ocmem_exit(void)
853{
854 platform_driver_unregister(&msm_ocmem_driver);
855}
856module_exit(ocmem_exit);
857
858MODULE_LICENSE("GPL v2");
859MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");