DSS2: VRFB rotation and mirroring implemented.
[pandora-kernel.git] / arch / arm / plat-omap / vrfb.c
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/ioport.h>
4 #include <asm/io.h>
5
6 #include <mach/io.h>
7 #include <mach/vrfb.h>
8 /*#define DEBUG*/
9
10 #ifdef DEBUG
11 #define DBG(format, ...) printk(KERN_DEBUG "VRFB: " format, ## __VA_ARGS__)
12 #else
13 #define DBG(format, ...)
14 #endif
15
16 #define SMS_ROT_VIRT_BASE(context, rot) \
17         (((context >= 4) ? 0xD0000000 : 0x70000000) \
18          + (0x4000000 * (context)) \
19          + (0x1000000 * (rot)))
20
21 #define OMAP_VRFB_SIZE                  (2048 * 2048 * 4)
22
23 #define VRFB_PAGE_WIDTH_EXP     5 /* Assuming SDRAM pagesize= 1024 */
24 #define VRFB_PAGE_HEIGHT_EXP    5 /* 1024 = 2^5 * 2^5 */
25 #define VRFB_PAGE_WIDTH         (1 << VRFB_PAGE_WIDTH_EXP)
26 #define VRFB_PAGE_HEIGHT        (1 << VRFB_PAGE_HEIGHT_EXP)
27 #define SMS_IMAGEHEIGHT_OFFSET  16
28 #define SMS_IMAGEWIDTH_OFFSET   0
29 #define SMS_PH_OFFSET           8
30 #define SMS_PW_OFFSET           4
31 #define SMS_PS_OFFSET           0
32
33 #define OMAP_SMS_BASE           0x6C000000
34 #define SMS_ROT_CONTROL(context)        (OMAP_SMS_BASE + 0x180 + 0x10 * context)
35 #define SMS_ROT_SIZE(context)           (OMAP_SMS_BASE + 0x184 + 0x10 * context)
36 #define SMS_ROT_PHYSICAL_BA(context)    (OMAP_SMS_BASE + 0x188 + 0x10 * context)
37
38 #define VRFB_NUM_CTXS 12
39 /* bitmap of reserved contexts */
40 static unsigned ctx_map;
41
42 void omap_vrfb_adjust_size(u16 *width, u16 *height,
43                 u8 bytespp)
44 {
45         *width = ALIGN(*width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
46         *height = ALIGN(*height, VRFB_PAGE_HEIGHT);
47 }
48 EXPORT_SYMBOL(omap_vrfb_adjust_size);
49
50 void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
51                 u16 width, u16 height,
52                 enum omap_color_mode color_mode)
53 {
54         unsigned pixel_size_exp;
55         u16 vrfb_width;
56         u16 vrfb_height;
57         u8 ctx = vrfb->context;
58         u8 bytespp;
59
60         DBG("omapfb_set_vrfb(%d, %lx, %dx%d, %d)\n", ctx, paddr,
61                         width, height, bytespp);
62
63         switch (color_mode) {
64         case OMAP_DSS_COLOR_RGB16:
65         case OMAP_DSS_COLOR_ARGB16:
66                 bytespp = 2;
67                 break;
68
69         case OMAP_DSS_COLOR_RGB24P:
70                 bytespp = 3;
71                 break;
72
73         case OMAP_DSS_COLOR_RGB24U:
74         case OMAP_DSS_COLOR_ARGB32:
75         case OMAP_DSS_COLOR_RGBA32:
76         case OMAP_DSS_COLOR_RGBX32:
77         case OMAP_DSS_COLOR_YUV2:
78         case OMAP_DSS_COLOR_UYVY:
79                 bytespp = 4;
80                 break;
81
82         default:
83                 BUG();
84                 return;
85         }
86
87         if (color_mode == OMAP_DSS_COLOR_YUV2 ||
88                         color_mode == OMAP_DSS_COLOR_UYVY)
89                 width >>= 1;
90
91         if (bytespp == 4) {
92                 pixel_size_exp = 2;
93         } else if (bytespp == 2)
94                 pixel_size_exp = 1;
95         else
96                 BUG();
97
98         vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
99         vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT);
100
101         DBG("vrfb w %u, h %u\n", vrfb_width, vrfb_height);
102
103         omap_writel(paddr, SMS_ROT_PHYSICAL_BA(ctx));
104         omap_writel((vrfb_width << SMS_IMAGEWIDTH_OFFSET) |
105                         (vrfb_height << SMS_IMAGEHEIGHT_OFFSET),
106                         SMS_ROT_SIZE(ctx));
107
108         omap_writel(pixel_size_exp << SMS_PS_OFFSET |
109                         VRFB_PAGE_WIDTH_EXP  << SMS_PW_OFFSET |
110                         VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET,
111                         SMS_ROT_CONTROL(ctx));
112
113         DBG("vrfb offset pixels %d, %d\n",
114                         vrfb_width - width, vrfb_height - height);
115
116         vrfb->xoffset = vrfb_width - width;
117         vrfb->yoffset = vrfb_height - height;
118         vrfb->bytespp = bytespp;
119 }
120 EXPORT_SYMBOL(omap_vrfb_setup);
121
122 void omap_vrfb_release_ctx(struct vrfb *vrfb)
123 {
124         int rot;
125
126         if (vrfb->context == 0xff)
127                 return;
128
129         DBG("release ctx %d\n", vrfb->context);
130
131         ctx_map &= ~(1 << vrfb->context);
132
133         for (rot = 0; rot < 4; ++rot) {
134                 if(vrfb->paddr[rot]) {
135                         release_mem_region(vrfb->paddr[rot], OMAP_VRFB_SIZE);
136                         vrfb->paddr[rot] = 0;
137                 }
138         }
139
140         vrfb->context = 0xff;
141 }
142 EXPORT_SYMBOL(omap_vrfb_release_ctx);
143
144 int omap_vrfb_request_ctx(struct vrfb *vrfb)
145 {
146         int rot;
147         u32 paddr;
148         u8 ctx;
149
150         DBG("request ctx\n");
151
152         for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx)
153                 if ((ctx_map & (1 << ctx)) == 0)
154                         break;
155
156         if (ctx == VRFB_NUM_CTXS) {
157                 printk(KERN_ERR "vrfb: no free contexts\n");
158                 return -EBUSY;
159         }
160
161         DBG("found free ctx %d\n", ctx);
162
163         ctx_map |= 1 << ctx;
164
165         memset(vrfb, 0, sizeof(*vrfb));
166
167         vrfb->context = ctx;
168
169         for (rot = 0; rot < 4; ++rot) {
170                 paddr = SMS_ROT_VIRT_BASE(ctx, rot);
171                 if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) {
172                         printk(KERN_ERR "vrfb: failed to reserve VRFB "
173                                         "area for ctx %d, rotation %d\n",
174                                         ctx, rot * 90);
175                         omap_vrfb_release_ctx(vrfb);
176                         return -ENOMEM;
177                 }
178
179                 vrfb->paddr[rot] = paddr;
180
181                 DBG("VRFB %d/%d: %lx\n", ctx, rot*90, vrfb->paddr[rot]);
182         }
183
184         return 0;
185 }
186 EXPORT_SYMBOL(omap_vrfb_request_ctx);
187