Merge tag 'sound-3.4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[pandora-kernel.git] / drivers / video / sh_mobile_meram.c
1 /*
2  * SuperH Mobile MERAM Driver for SuperH Mobile LCDC Driver
3  *
4  * Copyright (c) 2011   Damian Hobson-Garcia <dhobsong@igel.co.jp>
5  *                      Takanari Hayama <taki@igel.co.jp>
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file "COPYING" in the main directory of this archive
9  * for more details.
10  */
11
12 #include <linux/device.h>
13 #include <linux/err.h>
14 #include <linux/genalloc.h>
15 #include <linux/io.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/slab.h>
21
22 #include <video/sh_mobile_meram.h>
23
24 /* -----------------------------------------------------------------------------
25  * MERAM registers
26  */
27
28 #define MEVCR1                  0x4
29 #define MEVCR1_RST              (1 << 31)
30 #define MEVCR1_WD               (1 << 30)
31 #define MEVCR1_AMD1             (1 << 29)
32 #define MEVCR1_AMD0             (1 << 28)
33 #define MEQSEL1                 0x40
34 #define MEQSEL2                 0x44
35
36 #define MExxCTL                 0x400
37 #define MExxCTL_BV              (1 << 31)
38 #define MExxCTL_BSZ_SHIFT       28
39 #define MExxCTL_MSAR_MASK       (0x7ff << MExxCTL_MSAR_SHIFT)
40 #define MExxCTL_MSAR_SHIFT      16
41 #define MExxCTL_NXT_MASK        (0x1f << MExxCTL_NXT_SHIFT)
42 #define MExxCTL_NXT_SHIFT       11
43 #define MExxCTL_WD1             (1 << 10)
44 #define MExxCTL_WD0             (1 << 9)
45 #define MExxCTL_WS              (1 << 8)
46 #define MExxCTL_CB              (1 << 7)
47 #define MExxCTL_WBF             (1 << 6)
48 #define MExxCTL_WF              (1 << 5)
49 #define MExxCTL_RF              (1 << 4)
50 #define MExxCTL_CM              (1 << 3)
51 #define MExxCTL_MD_READ         (1 << 0)
52 #define MExxCTL_MD_WRITE        (2 << 0)
53 #define MExxCTL_MD_ICB_WB       (3 << 0)
54 #define MExxCTL_MD_ICB          (4 << 0)
55 #define MExxCTL_MD_FB           (7 << 0)
56 #define MExxCTL_MD_MASK         (7 << 0)
57 #define MExxBSIZE               0x404
58 #define MExxBSIZE_RCNT_SHIFT    28
59 #define MExxBSIZE_YSZM1_SHIFT   16
60 #define MExxBSIZE_XSZM1_SHIFT   0
61 #define MExxMNCF                0x408
62 #define MExxMNCF_KWBNM_SHIFT    28
63 #define MExxMNCF_KRBNM_SHIFT    24
64 #define MExxMNCF_BNM_SHIFT      16
65 #define MExxMNCF_XBV            (1 << 15)
66 #define MExxMNCF_CPL_YCBCR444   (1 << 12)
67 #define MExxMNCF_CPL_YCBCR420   (2 << 12)
68 #define MExxMNCF_CPL_YCBCR422   (3 << 12)
69 #define MExxMNCF_CPL_MSK        (3 << 12)
70 #define MExxMNCF_BL             (1 << 2)
71 #define MExxMNCF_LNM_SHIFT      0
72 #define MExxSARA                0x410
73 #define MExxSARB                0x414
74 #define MExxSBSIZE              0x418
75 #define MExxSBSIZE_HDV          (1 << 31)
76 #define MExxSBSIZE_HSZ16        (0 << 28)
77 #define MExxSBSIZE_HSZ32        (1 << 28)
78 #define MExxSBSIZE_HSZ64        (2 << 28)
79 #define MExxSBSIZE_HSZ128       (3 << 28)
80 #define MExxSBSIZE_SBSIZZ_SHIFT 0
81
82 #define MERAM_MExxCTL_VAL(next, addr)   \
83         ((((next) << MExxCTL_NXT_SHIFT) & MExxCTL_NXT_MASK) | \
84          (((addr) << MExxCTL_MSAR_SHIFT) & MExxCTL_MSAR_MASK))
85 #define MERAM_MExxBSIZE_VAL(rcnt, yszm1, xszm1) \
86         (((rcnt) << MExxBSIZE_RCNT_SHIFT) | \
87          ((yszm1) << MExxBSIZE_YSZM1_SHIFT) | \
88          ((xszm1) << MExxBSIZE_XSZM1_SHIFT))
89
90 static const unsigned long common_regs[] = {
91         MEVCR1,
92         MEQSEL1,
93         MEQSEL2,
94 };
95 #define MERAM_REGS_SIZE ARRAY_SIZE(common_regs)
96
97 static const unsigned long icb_regs[] = {
98         MExxCTL,
99         MExxBSIZE,
100         MExxMNCF,
101         MExxSARA,
102         MExxSARB,
103         MExxSBSIZE,
104 };
105 #define ICB_REGS_SIZE ARRAY_SIZE(icb_regs)
106
107 /*
108  * sh_mobile_meram_icb - MERAM ICB information
109  * @regs: Registers cache
110  * @index: ICB index
111  * @offset: MERAM block offset
112  * @size: MERAM block size in KiB
113  * @cache_unit: Bytes to cache per ICB
114  * @pixelformat: Video pixel format of the data stored in the ICB
115  * @current_reg: Which of Start Address Register A (0) or B (1) is in use
116  */
117 struct sh_mobile_meram_icb {
118         unsigned long regs[ICB_REGS_SIZE];
119         unsigned int index;
120         unsigned long offset;
121         unsigned int size;
122
123         unsigned int cache_unit;
124         unsigned int pixelformat;
125         unsigned int current_reg;
126 };
127
128 #define MERAM_ICB_NUM                   32
129
130 struct sh_mobile_meram_fb_plane {
131         struct sh_mobile_meram_icb *marker;
132         struct sh_mobile_meram_icb *cache;
133 };
134
135 struct sh_mobile_meram_fb_cache {
136         unsigned int nplanes;
137         struct sh_mobile_meram_fb_plane planes[2];
138 };
139
140 /*
141  * sh_mobile_meram_priv - MERAM device
142  * @base: Registers base address
143  * @meram: MERAM physical address
144  * @regs: Registers cache
145  * @lock: Protects used_icb and icbs
146  * @used_icb: Bitmask of used ICBs
147  * @icbs: ICBs
148  * @pool: Allocation pool to manage the MERAM
149  */
150 struct sh_mobile_meram_priv {
151         void __iomem *base;
152         unsigned long meram;
153         unsigned long regs[MERAM_REGS_SIZE];
154
155         struct mutex lock;
156         unsigned long used_icb;
157         struct sh_mobile_meram_icb icbs[MERAM_ICB_NUM];
158
159         struct gen_pool *pool;
160 };
161
162 /* settings */
163 #define MERAM_GRANULARITY               1024
164 #define MERAM_SEC_LINE                  15
165 #define MERAM_LINE_WIDTH                2048
166
167 /* -----------------------------------------------------------------------------
168  * Registers access
169  */
170
171 #define MERAM_ICB_OFFSET(base, idx, off)        ((base) + (off) + (idx) * 0x20)
172
173 static inline void meram_write_icb(void __iomem *base, unsigned int idx,
174                                    unsigned int off, unsigned long val)
175 {
176         iowrite32(val, MERAM_ICB_OFFSET(base, idx, off));
177 }
178
179 static inline unsigned long meram_read_icb(void __iomem *base, unsigned int idx,
180                                            unsigned int off)
181 {
182         return ioread32(MERAM_ICB_OFFSET(base, idx, off));
183 }
184
185 static inline void meram_write_reg(void __iomem *base, unsigned int off,
186                                    unsigned long val)
187 {
188         iowrite32(val, base + off);
189 }
190
191 static inline unsigned long meram_read_reg(void __iomem *base, unsigned int off)
192 {
193         return ioread32(base + off);
194 }
195
196 /* -----------------------------------------------------------------------------
197  * Allocation
198  */
199
200 /* Allocate ICBs and MERAM for a plane. */
201 static int __meram_alloc(struct sh_mobile_meram_priv *priv,
202                          struct sh_mobile_meram_fb_plane *plane,
203                          size_t size)
204 {
205         unsigned long mem;
206         unsigned long idx;
207
208         idx = find_first_zero_bit(&priv->used_icb, 28);
209         if (idx == 28)
210                 return -ENOMEM;
211         plane->cache = &priv->icbs[idx];
212
213         idx = find_next_zero_bit(&priv->used_icb, 32, 28);
214         if (idx == 32)
215                 return -ENOMEM;
216         plane->marker = &priv->icbs[idx];
217
218         mem = gen_pool_alloc(priv->pool, size * 1024);
219         if (mem == 0)
220                 return -ENOMEM;
221
222         __set_bit(plane->marker->index, &priv->used_icb);
223         __set_bit(plane->cache->index, &priv->used_icb);
224
225         plane->marker->offset = mem - priv->meram;
226         plane->marker->size = size;
227
228         return 0;
229 }
230
231 /* Free ICBs and MERAM for a plane. */
232 static void __meram_free(struct sh_mobile_meram_priv *priv,
233                          struct sh_mobile_meram_fb_plane *plane)
234 {
235         gen_pool_free(priv->pool, priv->meram + plane->marker->offset,
236                       plane->marker->size * 1024);
237
238         __clear_bit(plane->marker->index, &priv->used_icb);
239         __clear_bit(plane->cache->index, &priv->used_icb);
240 }
241
242 /* Is this a YCbCr(NV12, NV16 or NV24) colorspace? */
243 static int is_nvcolor(int cspace)
244 {
245         if (cspace == SH_MOBILE_MERAM_PF_NV ||
246             cspace == SH_MOBILE_MERAM_PF_NV24)
247                 return 1;
248         return 0;
249 }
250
251 /* Allocate memory for the ICBs and mark them as used. */
252 static struct sh_mobile_meram_fb_cache *
253 meram_alloc(struct sh_mobile_meram_priv *priv,
254             const struct sh_mobile_meram_cfg *cfg,
255             int pixelformat)
256 {
257         struct sh_mobile_meram_fb_cache *cache;
258         unsigned int nplanes = is_nvcolor(pixelformat) ? 2 : 1;
259         int ret;
260
261         if (cfg->icb[0].meram_size == 0)
262                 return ERR_PTR(-EINVAL);
263
264         if (nplanes == 2 && cfg->icb[1].meram_size == 0)
265                 return ERR_PTR(-EINVAL);
266
267         cache = kzalloc(sizeof(*cache), GFP_KERNEL);
268         if (cache == NULL)
269                 return ERR_PTR(-ENOMEM);
270
271         cache->nplanes = nplanes;
272
273         ret = __meram_alloc(priv, &cache->planes[0], cfg->icb[0].meram_size);
274         if (ret < 0)
275                 goto error;
276
277         cache->planes[0].marker->current_reg = 1;
278         cache->planes[0].marker->pixelformat = pixelformat;
279
280         if (cache->nplanes == 1)
281                 return cache;
282
283         ret = __meram_alloc(priv, &cache->planes[1], cfg->icb[1].meram_size);
284         if (ret < 0) {
285                 __meram_free(priv, &cache->planes[0]);
286                 goto error;
287         }
288
289         return cache;
290
291 error:
292         kfree(cache);
293         return ERR_PTR(-ENOMEM);
294 }
295
296 /* Unmark the specified ICB as used. */
297 static void meram_free(struct sh_mobile_meram_priv *priv,
298                        struct sh_mobile_meram_fb_cache *cache)
299 {
300         __meram_free(priv, &cache->planes[0]);
301         if (cache->nplanes == 2)
302                 __meram_free(priv, &cache->planes[1]);
303
304         kfree(cache);
305 }
306
307 /* Set the next address to fetch. */
308 static void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
309                                 struct sh_mobile_meram_fb_cache *cache,
310                                 unsigned long base_addr_y,
311                                 unsigned long base_addr_c)
312 {
313         struct sh_mobile_meram_icb *icb = cache->planes[0].marker;
314         unsigned long target;
315
316         icb->current_reg ^= 1;
317         target = icb->current_reg ? MExxSARB : MExxSARA;
318
319         /* set the next address to fetch */
320         meram_write_icb(priv->base, cache->planes[0].cache->index, target,
321                         base_addr_y);
322         meram_write_icb(priv->base, cache->planes[0].marker->index, target,
323                         base_addr_y + cache->planes[0].marker->cache_unit);
324
325         if (cache->nplanes == 2) {
326                 meram_write_icb(priv->base, cache->planes[1].cache->index,
327                                 target, base_addr_c);
328                 meram_write_icb(priv->base, cache->planes[1].marker->index,
329                                 target, base_addr_c +
330                                 cache->planes[1].marker->cache_unit);
331         }
332 }
333
334 /* Get the next ICB address. */
335 static void
336 meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
337                         struct sh_mobile_meram_fb_cache *cache,
338                         unsigned long *icb_addr_y, unsigned long *icb_addr_c)
339 {
340         struct sh_mobile_meram_icb *icb = cache->planes[0].marker;
341         unsigned long icb_offset;
342
343         if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0)
344                 icb_offset = 0x80000000 | (icb->current_reg << 29);
345         else
346                 icb_offset = 0xc0000000 | (icb->current_reg << 23);
347
348         *icb_addr_y = icb_offset | (cache->planes[0].marker->index << 24);
349         if (cache->nplanes == 2)
350                 *icb_addr_c = icb_offset
351                             | (cache->planes[1].marker->index << 24);
352 }
353
354 #define MERAM_CALC_BYTECOUNT(x, y) \
355         (((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1))
356
357 /* Initialize MERAM. */
358 static int meram_init(struct sh_mobile_meram_priv *priv,
359                       struct sh_mobile_meram_fb_plane *plane,
360                       unsigned int xres, unsigned int yres,
361                       unsigned int *out_pitch)
362 {
363         struct sh_mobile_meram_icb *marker = plane->marker;
364         unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
365         unsigned long bnm;
366         unsigned int lcdc_pitch;
367         unsigned int xpitch;
368         unsigned int line_cnt;
369         unsigned int save_lines;
370
371         /* adjust pitch to 1024, 2048, 4096 or 8192 */
372         lcdc_pitch = (xres - 1) | 1023;
373         lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 1);
374         lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 2);
375         lcdc_pitch += 1;
376
377         /* derive settings */
378         if (lcdc_pitch == 8192 && yres >= 1024) {
379                 lcdc_pitch = xpitch = MERAM_LINE_WIDTH;
380                 line_cnt = total_byte_count >> 11;
381                 *out_pitch = xres;
382                 save_lines = plane->marker->size / 16 / MERAM_SEC_LINE;
383                 save_lines *= MERAM_SEC_LINE;
384         } else {
385                 xpitch = xres;
386                 line_cnt = yres;
387                 *out_pitch = lcdc_pitch;
388                 save_lines = plane->marker->size / (lcdc_pitch >> 10) / 2;
389                 save_lines &= 0xff;
390         }
391         bnm = (save_lines - 1) << 16;
392
393         /* TODO: we better to check if we have enough MERAM buffer size */
394
395         /* set up ICB */
396         meram_write_icb(priv->base, plane->cache->index,  MExxBSIZE,
397                         MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1));
398         meram_write_icb(priv->base, plane->marker->index, MExxBSIZE,
399                         MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1));
400
401         meram_write_icb(priv->base, plane->cache->index,  MExxMNCF, bnm);
402         meram_write_icb(priv->base, plane->marker->index, MExxMNCF, bnm);
403
404         meram_write_icb(priv->base, plane->cache->index,  MExxSBSIZE, xpitch);
405         meram_write_icb(priv->base, plane->marker->index, MExxSBSIZE, xpitch);
406
407         /* save a cache unit size */
408         plane->cache->cache_unit = xres * save_lines;
409         plane->marker->cache_unit = xres * save_lines;
410
411         /*
412          * Set MERAM for framebuffer
413          *
414          * we also chain the cache_icb and the marker_icb.
415          * we also split the allocated MERAM buffer between two ICBs.
416          */
417         meram_write_icb(priv->base, plane->cache->index, MExxCTL,
418                         MERAM_MExxCTL_VAL(plane->marker->index, marker->offset)
419                         | MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
420                         MExxCTL_MD_FB);
421         meram_write_icb(priv->base, plane->marker->index, MExxCTL,
422                         MERAM_MExxCTL_VAL(plane->cache->index, marker->offset +
423                                           plane->marker->size / 2) |
424                         MExxCTL_WD1 | MExxCTL_WD0 | MExxCTL_WS | MExxCTL_CM |
425                         MExxCTL_MD_FB);
426
427         return 0;
428 }
429
430 static void meram_deinit(struct sh_mobile_meram_priv *priv,
431                          struct sh_mobile_meram_fb_plane *plane)
432 {
433         /* disable ICB */
434         meram_write_icb(priv->base, plane->cache->index,  MExxCTL,
435                         MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
436         meram_write_icb(priv->base, plane->marker->index, MExxCTL,
437                         MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF);
438
439         plane->cache->cache_unit = 0;
440         plane->marker->cache_unit = 0;
441 }
442
443 /* -----------------------------------------------------------------------------
444  * Registration/unregistration
445  */
446
447 static void *sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
448                                       const struct sh_mobile_meram_cfg *cfg,
449                                       unsigned int xres, unsigned int yres,
450                                       unsigned int pixelformat,
451                                       unsigned int *pitch)
452 {
453         struct sh_mobile_meram_fb_cache *cache;
454         struct sh_mobile_meram_priv *priv = pdata->priv;
455         struct platform_device *pdev = pdata->pdev;
456         unsigned int out_pitch;
457
458         if (pixelformat != SH_MOBILE_MERAM_PF_NV &&
459             pixelformat != SH_MOBILE_MERAM_PF_NV24 &&
460             pixelformat != SH_MOBILE_MERAM_PF_RGB)
461                 return ERR_PTR(-EINVAL);
462
463         dev_dbg(&pdev->dev, "registering %dx%d (%s)", xres, yres,
464                 !pixelformat ? "yuv" : "rgb");
465
466         /* we can't handle wider than 8192px */
467         if (xres > 8192) {
468                 dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
469                 return ERR_PTR(-EINVAL);
470         }
471
472         mutex_lock(&priv->lock);
473
474         /* We now register the ICBs and allocate the MERAM regions. */
475         cache = meram_alloc(priv, cfg, pixelformat);
476         if (IS_ERR(cache)) {
477                 dev_err(&pdev->dev, "MERAM allocation failed (%ld).",
478                         PTR_ERR(cache));
479                 goto err;
480         }
481
482         /* initialize MERAM */
483         meram_init(priv, &cache->planes[0], xres, yres, &out_pitch);
484         *pitch = out_pitch;
485         if (pixelformat == SH_MOBILE_MERAM_PF_NV)
486                 meram_init(priv, &cache->planes[1], xres, (yres + 1) / 2,
487                         &out_pitch);
488         else if (pixelformat == SH_MOBILE_MERAM_PF_NV24)
489                 meram_init(priv, &cache->planes[1], 2 * xres, (yres + 1) / 2,
490                         &out_pitch);
491
492 err:
493         mutex_unlock(&priv->lock);
494         return cache;
495 }
496
497 static void
498 sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata, void *data)
499 {
500         struct sh_mobile_meram_fb_cache *cache = data;
501         struct sh_mobile_meram_priv *priv = pdata->priv;
502
503         mutex_lock(&priv->lock);
504
505         /* deinit & free */
506         meram_deinit(priv, &cache->planes[0]);
507         if (cache->nplanes == 2)
508                 meram_deinit(priv, &cache->planes[1]);
509
510         meram_free(priv, cache);
511
512         mutex_unlock(&priv->lock);
513 }
514
515 static void
516 sh_mobile_meram_update(struct sh_mobile_meram_info *pdata, void *data,
517                        unsigned long base_addr_y, unsigned long base_addr_c,
518                        unsigned long *icb_addr_y, unsigned long *icb_addr_c)
519 {
520         struct sh_mobile_meram_fb_cache *cache = data;
521         struct sh_mobile_meram_priv *priv = pdata->priv;
522
523         mutex_lock(&priv->lock);
524
525         meram_set_next_addr(priv, cache, base_addr_y, base_addr_c);
526         meram_get_next_icb_addr(pdata, cache, icb_addr_y, icb_addr_c);
527
528         mutex_unlock(&priv->lock);
529 }
530
531 static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
532         .module                 = THIS_MODULE,
533         .meram_register         = sh_mobile_meram_register,
534         .meram_unregister       = sh_mobile_meram_unregister,
535         .meram_update           = sh_mobile_meram_update,
536 };
537
538 /* -----------------------------------------------------------------------------
539  * Power management
540  */
541
542 static int sh_mobile_meram_suspend(struct device *dev)
543 {
544         struct platform_device *pdev = to_platform_device(dev);
545         struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
546         unsigned int i, j;
547
548         for (i = 0; i < MERAM_REGS_SIZE; i++)
549                 priv->regs[i] = meram_read_reg(priv->base, common_regs[i]);
550
551         for (i = 0; i < 32; i++) {
552                 if (!test_bit(i, &priv->used_icb))
553                         continue;
554                 for (j = 0; j < ICB_REGS_SIZE; j++) {
555                         priv->icbs[i].regs[j] =
556                                 meram_read_icb(priv->base, i, icb_regs[j]);
557                         /* Reset ICB on resume */
558                         if (icb_regs[j] == MExxCTL)
559                                 priv->icbs[i].regs[j] |=
560                                         MExxCTL_WBF | MExxCTL_WF | MExxCTL_RF;
561                 }
562         }
563         return 0;
564 }
565
566 static int sh_mobile_meram_resume(struct device *dev)
567 {
568         struct platform_device *pdev = to_platform_device(dev);
569         struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
570         unsigned int i, j;
571
572         for (i = 0; i < 32; i++) {
573                 if (!test_bit(i, &priv->used_icb))
574                         continue;
575                 for (j = 0; j < ICB_REGS_SIZE; j++)
576                         meram_write_icb(priv->base, i, icb_regs[j],
577                                         priv->icbs[i].regs[j]);
578         }
579
580         for (i = 0; i < MERAM_REGS_SIZE; i++)
581                 meram_write_reg(priv->base, common_regs[i], priv->regs[i]);
582         return 0;
583 }
584
585 static UNIVERSAL_DEV_PM_OPS(sh_mobile_meram_dev_pm_ops,
586                             sh_mobile_meram_suspend,
587                             sh_mobile_meram_resume, NULL);
588
589 /* -----------------------------------------------------------------------------
590  * Probe/remove and driver init/exit
591  */
592
593 static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
594 {
595         struct sh_mobile_meram_priv *priv;
596         struct sh_mobile_meram_info *pdata = pdev->dev.platform_data;
597         struct resource *regs;
598         struct resource *meram;
599         unsigned int i;
600         int error;
601
602         if (!pdata) {
603                 dev_err(&pdev->dev, "no platform data defined\n");
604                 return -EINVAL;
605         }
606
607         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
608         meram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
609         if (regs == NULL || meram == NULL) {
610                 dev_err(&pdev->dev, "cannot get platform resources\n");
611                 return -ENOENT;
612         }
613
614         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
615         if (!priv) {
616                 dev_err(&pdev->dev, "cannot allocate device data\n");
617                 return -ENOMEM;
618         }
619
620         /* Initialize private data. */
621         mutex_init(&priv->lock);
622         priv->used_icb = pdata->reserved_icbs;
623
624         for (i = 0; i < MERAM_ICB_NUM; ++i)
625                 priv->icbs[i].index = i;
626
627         pdata->ops = &sh_mobile_meram_ops;
628         pdata->priv = priv;
629         pdata->pdev = pdev;
630
631         /* Request memory regions and remap the registers. */
632         if (!request_mem_region(regs->start, resource_size(regs), pdev->name)) {
633                 dev_err(&pdev->dev, "MERAM registers region already claimed\n");
634                 error = -EBUSY;
635                 goto err_req_regs;
636         }
637
638         if (!request_mem_region(meram->start, resource_size(meram),
639                                 pdev->name)) {
640                 dev_err(&pdev->dev, "MERAM memory region already claimed\n");
641                 error = -EBUSY;
642                 goto err_req_meram;
643         }
644
645         priv->base = ioremap_nocache(regs->start, resource_size(regs));
646         if (!priv->base) {
647                 dev_err(&pdev->dev, "ioremap failed\n");
648                 error = -EFAULT;
649                 goto err_ioremap;
650         }
651
652         priv->meram = meram->start;
653
654         /* Create and initialize the MERAM memory pool. */
655         priv->pool = gen_pool_create(ilog2(MERAM_GRANULARITY), -1);
656         if (priv->pool == NULL) {
657                 error = -ENOMEM;
658                 goto err_genpool;
659         }
660
661         error = gen_pool_add(priv->pool, meram->start, resource_size(meram),
662                              -1);
663         if (error < 0)
664                 goto err_genpool;
665
666         /* initialize ICB addressing mode */
667         if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
668                 meram_write_reg(priv->base, MEVCR1, MEVCR1_AMD1);
669
670         platform_set_drvdata(pdev, priv);
671         pm_runtime_enable(&pdev->dev);
672
673         dev_info(&pdev->dev, "sh_mobile_meram initialized.");
674
675         return 0;
676
677 err_genpool:
678         if (priv->pool)
679                 gen_pool_destroy(priv->pool);
680         iounmap(priv->base);
681 err_ioremap:
682         release_mem_region(meram->start, resource_size(meram));
683 err_req_meram:
684         release_mem_region(regs->start, resource_size(regs));
685 err_req_regs:
686         mutex_destroy(&priv->lock);
687         kfree(priv);
688
689         return error;
690 }
691
692
693 static int sh_mobile_meram_remove(struct platform_device *pdev)
694 {
695         struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
696         struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
697         struct resource *meram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
698
699         pm_runtime_disable(&pdev->dev);
700
701         gen_pool_destroy(priv->pool);
702
703         iounmap(priv->base);
704         release_mem_region(meram->start, resource_size(meram));
705         release_mem_region(regs->start, resource_size(regs));
706
707         mutex_destroy(&priv->lock);
708
709         kfree(priv);
710
711         return 0;
712 }
713
714 static struct platform_driver sh_mobile_meram_driver = {
715         .driver = {
716                 .name           = "sh_mobile_meram",
717                 .owner          = THIS_MODULE,
718                 .pm             = &sh_mobile_meram_dev_pm_ops,
719         },
720         .probe          = sh_mobile_meram_probe,
721         .remove         = sh_mobile_meram_remove,
722 };
723
724 module_platform_driver(sh_mobile_meram_driver);
725
726 MODULE_DESCRIPTION("SuperH Mobile MERAM driver");
727 MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama");
728 MODULE_LICENSE("GPL v2");