blob: 17297423f5c420e122ce28ede9e4365f43b598ac [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
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700590static int ocmem_zone_init(struct platform_device *pdev)
591{
592
593 int ret = -1;
594 int i = 0;
595 unsigned active_zones = 0;
596
597 struct ocmem_zone *zone = NULL;
598 struct ocmem_zone_ops *z_ops = NULL;
599 struct device *dev = &pdev->dev;
600 unsigned long start;
601 struct ocmem_plat_data *pdata = NULL;
602
603 pdata = platform_get_drvdata(pdev);
604
605 for (i = 0; i < pdata->nr_parts; i++) {
606 struct ocmem_partition *part = &pdata->parts[i];
607 zone = get_zone(part->id);
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700608 zone->active = false;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700609
610 dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
611 i, part->p_start, part->p_size,
612 client_names[part->id]);
613
614 if (part->p_size > pdata->size) {
615 dev_alert(dev, "Quota > ocmem_size for id:%d\n",
616 part->id);
617 continue;
618 }
619
620 zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
621
622 if (!zone->z_pool) {
623 dev_alert(dev, "Creating pool failed for id:%d\n",
624 part->id);
625 return -EBUSY;
626 }
627
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700628 start = part->p_start;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700629 ret = gen_pool_add(zone->z_pool, start,
630 part->p_size, -1);
631
632 if (ret < 0) {
633 gen_pool_destroy(zone->z_pool);
634 dev_alert(dev, "Unable to back pool %d with "
635 "buffer:%lx\n", part->id, part->p_size);
636 return -EBUSY;
637 }
638
639 /* Initialize zone allocators */
640 z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
641 GFP_KERNEL);
642 if (!z_ops) {
643 pr_alert("ocmem: Unable to allocate memory for"
644 "zone ops:%d\n", i);
645 return -EBUSY;
646 }
647
648 /* Initialize zone parameters */
649 zone->z_start = start;
650 zone->z_head = zone->z_start;
651 zone->z_end = start + part->p_size;
652 zone->z_tail = zone->z_end;
653 zone->z_free = part->p_size;
654 zone->owner = part->id;
655 zone->active_regions = 0;
656 zone->max_regions = 0;
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700657 INIT_LIST_HEAD(&zone->req_list);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700658 zone->z_ops = z_ops;
Naveen Ramaraj135cd672012-04-23 12:13:28 -0700659 if (part->p_tail) {
660 z_ops->allocate = allocate_tail;
661 z_ops->free = free_tail;
662 } else {
663 z_ops->allocate = allocate_head;
664 z_ops->free = free_head;
665 }
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700666 /* zap the counters */
667 memset(zone->z_stat, 0 , sizeof(zone->z_stat));
Naveen Ramaraj4d5e3542012-08-12 21:55:49 -0700668 zone->active = true;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700669 active_zones++;
670
671 if (active_zones == 1)
672 pr_info("Physical OCMEM zone layout:\n");
673
674 pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
675 client_names[part->id], zone->z_start,
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700676 zone->z_end - 1, part->p_size/SZ_1K);
677 }
678
679 if (!debugfs_create_file("zones", S_IRUGO, pdata->debug_node,
680 NULL, &zones_show_fops)) {
681 dev_err(dev, "Unable to create debugfs node for zones\n");
682 return -EBUSY;
683 }
684
685 if (!debugfs_create_file("stats", S_IRUGO, pdata->debug_node,
686 NULL, &stats_show_fops)) {
687 dev_err(dev, "Unable to create debugfs node for stats\n");
688 return -EBUSY;
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700689 }
690
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700691 dev_dbg(dev, "Total active zones = %d\n", active_zones);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700692 return 0;
693}
694
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700695/* Enable the ocmem graphics mpU as a workaround */
696/* This will be programmed by TZ after TZ support is integrated */
697static int ocmem_init_gfx_mpu(struct platform_device *pdev)
698{
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700699 int rc;
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700700 struct device *dev = &pdev->dev;
701 void __iomem *ocmem_region_vbase = NULL;
702
703 ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
704 OCMEM_REGION_CTL_SIZE);
705 if (!ocmem_region_vbase)
706 return -EBUSY;
707
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700708 rc = ocmem_enable_core_clock();
709
710 if (rc < 0)
711 return rc;
712
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700713 writel_relaxed(GRAPHICS_REGION_CTL, ocmem_region_vbase + 0xFCC);
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700714 ocmem_disable_core_clock();
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700715 return 0;
716}
717
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700718static int __devinit ocmem_debugfs_init(struct platform_device *pdev)
719{
720 struct dentry *debug_dir = NULL;
721 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
722
723 debug_dir = debugfs_create_dir("ocmem", NULL);
724 if (!debug_dir || IS_ERR(debug_dir)) {
725 pr_err("ocmem: Unable to create debugfs root\n");
726 return PTR_ERR(debug_dir);
727 }
728
729 pdata->debug_node = debug_dir;
730 return 0;
731}
732
733static void __devexit ocmem_debugfs_exit(struct platform_device *pdev)
734{
735 struct ocmem_plat_data *pdata = platform_get_drvdata(pdev);
736 debugfs_remove_recursive(pdata->debug_node);
737}
738
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700739static int __devinit msm_ocmem_probe(struct platform_device *pdev)
740{
741 struct device *dev = &pdev->dev;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700742 struct clk *ocmem_core_clk = NULL;
743 struct clk *ocmem_iface_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
Neeti Desai8297364b2013-02-05 17:16:36 -0800777 if (IS_ERR_OR_NULL(ocmem_iface_clk))
778 ocmem_iface_clk = NULL;
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700779
Naveen Ramaraj5da54542012-08-21 13:26:17 -0700780
Naveen Ramarajbea2d5d2012-08-15 17:26:43 -0700781 ocmem_pdata->core_clk = ocmem_core_clk;
782 ocmem_pdata->iface_clk = ocmem_iface_clk;
783
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700784 platform_set_drvdata(pdev, ocmem_pdata);
785
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700786 if (ocmem_debugfs_init(pdev))
787 return -EBUSY;
788
Naveen Ramaraj99b07562012-05-28 20:57:09 -0700789 if (ocmem_core_init(pdev))
790 return -EBUSY;
791
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700792 if (ocmem_zone_init(pdev))
793 return -EBUSY;
794
Naveen Ramarajbdf4dfe2012-04-23 14:09:50 -0700795 if (ocmem_notifier_init())
796 return -EBUSY;
797
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700798 if (ocmem_sched_init(pdev))
Naveen Ramarajb9da05782012-05-07 09:07:35 -0700799 return -EBUSY;
Naveen Ramaraj5b0982b2012-06-20 23:02:33 -0700800
Naveen Ramarajcc4ec152012-05-14 09:55:29 -0700801 if (ocmem_rdm_init(pdev))
802 return -EBUSY;
803
Naveen Ramaraj54ca8c02012-08-15 17:18:46 -0700804 if (ocmem_init_gfx_mpu(pdev)) {
805 dev_err(dev, "Unable to initialize Graphics mPU\n");
806 return -EBUSY;
807 }
808
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700809 dev_dbg(dev, "initialized successfully\n");
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700810 return 0;
811}
812
813static int __devexit msm_ocmem_remove(struct platform_device *pdev)
814{
Naveen Ramaraj6a92b262012-07-30 17:36:24 -0700815 ocmem_debugfs_exit(pdev);
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700816 return 0;
817}
818
819static struct of_device_id msm_ocmem_dt_match[] = {
Naveen Ramaraj8ad63602012-05-09 20:50:39 -0700820 { .compatible = "qcom,msm-ocmem",
Naveen Ramaraj51f5e8b2012-04-09 15:58:40 -0700821 },
822 {}
823};
824
825static struct platform_driver msm_ocmem_driver = {
826 .probe = msm_ocmem_probe,
827 .remove = __devexit_p(msm_ocmem_remove),
828 .driver = {
829 .name = "msm_ocmem",
830 .owner = THIS_MODULE,
831 .of_match_table = msm_ocmem_dt_match,
832 },
833};
834
835static int __init ocmem_init(void)
836{
837 return platform_driver_register(&msm_ocmem_driver);
838}
839subsys_initcall(ocmem_init);
840
841static void __exit ocmem_exit(void)
842{
843 platform_driver_unregister(&msm_ocmem_driver);
844}
845module_exit(ocmem_exit);
846
847MODULE_LICENSE("GPL v2");
848MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");