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