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