Commit da6cf5125f66ed1810616937777884cea021e66a

Authored by Laurent Pinchart
Committed by Florian Tobias Schandinat
1 parent 3c8a63e22a

sh_mobile_meram: Reset ICBs at unregistration time

When ICBs are unregistered and later reused they need to be reset to
avoid data corruption. Set the WBF, WF and RF bits to make sure ICBs get
reset properly.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>

Showing 1 changed file with 4 additions and 2 deletions Inline Diff

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