blob: 6ed004e40855097b9d8a445454580cdd6a811719 [file] [log] [blame]
Mike Rapoport67088d42015-09-22 12:01:16 +03001#include <linux/kernel.h>
2#include <linux/module.h>
3#include <linux/errno.h>
4#include <linux/string.h>
5#include <linux/mm.h>
6#include <linux/slab.h>
7#include <linux/delay.h>
8#include <linux/fb.h>
9#include <linux/ioport.h>
10#include <linux/init.h>
11#include <linux/pci.h>
12#include <linux/mm_types.h>
13#include <linux/vmalloc.h>
14#include <linux/pagemap.h>
15#include <linux/screen_info.h>
Sudip Mukherjee81dee672015-03-03 16:21:06 +053016#include <linux/console.h>
Sudip Mukherjee81dee672015-03-03 16:21:06 +053017#include <asm/fb.h>
18#include "sm750.h"
Sudip Mukherjee81dee672015-03-03 16:21:06 +053019#include "sm750_accel.h"
20#include "sm750_cursor.h"
21
Sudip Mukherjee81dee672015-03-03 16:21:06 +053022/*
Michel von Czettritzc52c3702015-03-26 23:24:32 +010023 * #ifdef __BIG_ENDIAN
24 * ssize_t lynxfb_ops_write(struct fb_info *info, const char __user *buf,
25 * size_t count, loff_t *ppos);
26 * ssize_t lynxfb_ops_read(struct fb_info *info, char __user *buf,
27 * size_t count, loff_t *ppos);
28 * #endif
Sudip Mukherjee81dee672015-03-03 16:21:06 +053029 */
30
Sudip Mukherjee81dee672015-03-03 16:21:06 +053031/* common var for all device */
32static int g_hwcursor = 1;
Supriya Karanthb30edfc2015-03-12 13:26:21 +090033static int g_noaccel;
Supriya Karanthb30edfc2015-03-12 13:26:21 +090034static int g_nomtrr;
Michel von Czettritz27fa1592015-03-26 23:25:37 +010035static const char *g_fbmode[] = {NULL, NULL};
36static const char *g_def_fbmode = "800x600-16@60";
Vinay Simha BNdf525682015-07-14 19:15:28 +053037static char *g_settings;
Supriya Karanthb30edfc2015-03-12 13:26:21 +090038static int g_dualview;
Vinay Simha BNdf525682015-07-14 19:15:28 +053039static char *g_option;
Michel von Czettritz27fa1592015-03-26 23:25:37 +010040
Sudip Mukherjee81dee672015-03-03 16:21:06 +053041static const struct fb_videomode lynx750_ext[] = {
Michel von Czettritz4bd95032015-03-26 23:26:04 +010042 /* 1024x600-60 VESA [1.71:1] */
Sudip Mukherjee81dee672015-03-03 16:21:06 +053043 {NULL, 60, 1024, 600, 20423, 144, 40, 18, 1, 104, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010044 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
45 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053046
Michel von Czettritz4bd95032015-03-26 23:26:04 +010047 /* 1024x600-70 VESA */
Sudip Mukherjee81dee672015-03-03 16:21:06 +053048 {NULL, 70, 1024, 600, 17211, 152, 48, 21, 1, 104, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010049 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
50 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053051
Michel von Czettritz4bd95032015-03-26 23:26:04 +010052 /* 1024x600-75 VESA */
Sudip Mukherjee81dee672015-03-03 16:21:06 +053053 {NULL, 75, 1024, 600, 15822, 160, 56, 23, 1, 104, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010054 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
55 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053056
Michel von Czettritz4bd95032015-03-26 23:26:04 +010057 /* 1024x600-85 VESA */
Sudip Mukherjee81dee672015-03-03 16:21:06 +053058 {NULL, 85, 1024, 600, 13730, 168, 56, 26, 1, 112, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010059 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
60 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053061
62 /* 720x480 */
63 {NULL, 60, 720, 480, 37427, 88, 16, 13, 1, 72, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010064 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
65 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053066
67 /* 1280x720 [1.78:1] */
68 {NULL, 60, 1280, 720, 13426, 162, 86, 22, 1, 136, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010069 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
70 FB_VMODE_NONINTERLACED},
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +010071
Michel von Czettritz4bd95032015-03-26 23:26:04 +010072 /* 1280x768@60 */
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +010073 {NULL, 60, 1280, 768, 12579, 192, 64, 20, 3, 128, 7,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010074 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
75 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053076
Sudip Mukherjee81dee672015-03-03 16:21:06 +053077 /* 1360 x 768 [1.77083:1] */
78 {NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010079 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
80 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053081
82 /* 1368 x 768 [1.78:1] */
83 {NULL, 60, 1368, 768, 11647, 216, 72, 23, 1, 144, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010084 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
85 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053086
Michel von Czettritz4bd95032015-03-26 23:26:04 +010087 /* 1440 x 900 [16:10] */
Sudip Mukherjee81dee672015-03-03 16:21:06 +053088 {NULL, 60, 1440, 900, 9392, 232, 80, 28, 1, 152, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010089 FB_SYNC_VERT_HIGH_ACT,
90 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053091
92 /* 1440x960 [15:10] */
93 {NULL, 60, 1440, 960, 8733, 240, 88, 30, 1, 152, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010094 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
95 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +053096
97 /* 1920x1080 [16:9] */
98 {NULL, 60, 1920, 1080, 6734, 148, 88, 41, 1, 44, 3,
Michel von Czettritz3318bb52015-03-26 23:26:23 +010099 FB_SYNC_VERT_HIGH_ACT,
100 FB_VMODE_NONINTERLACED},
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530101};
102
103
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530104/* no hardware cursor supported under version 2.6.10, kernel bug */
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100105static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530106{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100107 struct lynxfb_par *par;
108 struct lynxfb_crtc *crtc;
109 struct lynx_cursor *cursor;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530110
111 par = info->par;
112 crtc = &par->crtc;
113 cursor = &crtc->cursor;
114
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100115 if (fbcursor->image.width > cursor->maxW ||
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100116 fbcursor->image.height > cursor->maxH ||
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100117 fbcursor->image.depth > 1) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530118 return -ENXIO;
119 }
120
Mike Rapoportfb7f4052015-10-26 09:05:50 +0200121 hw_cursor_disable(cursor);
Michel von Czettritzf46a04c2015-03-27 19:42:48 +0100122 if (fbcursor->set & FB_CUR_SETSIZE)
Mike Rapoportfb7f4052015-10-26 09:05:50 +0200123 hw_cursor_setSize(cursor,
124 fbcursor->image.width,
125 fbcursor->image.height);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530126
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100127 if (fbcursor->set & FB_CUR_SETPOS)
Mike Rapoportfb7f4052015-10-26 09:05:50 +0200128 hw_cursor_setPos(cursor,
129 fbcursor->image.dx - info->var.xoffset,
130 fbcursor->image.dy - info->var.yoffset);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530131
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100132 if (fbcursor->set & FB_CUR_SETCMAP) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530133 /* get the 16bit color of kernel means */
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100134 u16 fg, bg;
Michel von Czettritz876e5a72015-03-26 23:26:37 +0100135
Sudip Mukherjee13ef3452015-08-07 17:34:03 +0530136 fg = ((info->cmap.red[fbcursor->image.fg_color] & 0xf800)) |
137 ((info->cmap.green[fbcursor->image.fg_color] & 0xfc00) >> 5) |
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100138 ((info->cmap.blue[fbcursor->image.fg_color] & 0xf800) >> 11);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530139
Sudip Mukherjee13ef3452015-08-07 17:34:03 +0530140 bg = ((info->cmap.red[fbcursor->image.bg_color] & 0xf800)) |
141 ((info->cmap.green[fbcursor->image.bg_color] & 0xfc00) >> 5) |
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100142 ((info->cmap.blue[fbcursor->image.bg_color] & 0xf800) >> 11);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530143
Mike Rapoportfb7f4052015-10-26 09:05:50 +0200144 hw_cursor_setColor(cursor, fg, bg);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530145 }
146
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100147 if (fbcursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
Mike Rapoportfb7f4052015-10-26 09:05:50 +0200148 hw_cursor_setData(cursor,
149 fbcursor->rop,
150 fbcursor->image.data,
151 fbcursor->mask);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530152 }
153
Michel von Czettritzf46a04c2015-03-27 19:42:48 +0100154 if (fbcursor->enable)
Mike Rapoportfb7f4052015-10-26 09:05:50 +0200155 hw_cursor_enable(cursor);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530156
157 return 0;
158}
159
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100160static void lynxfb_ops_fillrect(struct fb_info *info,
161 const struct fb_fillrect *region)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530162{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100163 struct lynxfb_par *par;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200164 struct sm750_dev *sm750_dev;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100165 unsigned int base, pitch, Bpp, rop;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530166 u32 color;
167
Michel von Czettritzf46a04c2015-03-27 19:42:48 +0100168 if (info->state != FBINFO_STATE_RUNNING)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530169 return;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530170
171 par = info->par;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200172 sm750_dev = par->dev;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530173
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +0530174 /*
175 * each time 2d function begin to work,below three variable always need
176 * be set, seems we can put them together in some place
177 */
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530178 base = par->crtc.oScreen;
179 pitch = info->fix.line_length;
180 Bpp = info->var.bits_per_pixel >> 3;
181
Sudip Mukherjee13ef3452015-08-07 17:34:03 +0530182 color = (Bpp == 1) ? region->color :
183 ((u32 *)info->pseudo_palette)[region->color];
184 rop = (region->rop != ROP_COPY) ? HW_ROP2_XOR : HW_ROP2_COPY;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530185
Lorenzo Stoakescb422f32015-03-20 15:22:15 +0000186 /*
187 * If not use spin_lock,system will die if user load driver
Carlos E. Garcia69e98df2015-04-24 09:40:42 -0400188 * and immediately unload driver frequently (dual)
Lorenzo Stoakescb422f32015-03-20 15:22:15 +0000189 */
Mike Rapoporta3f92cc2016-01-17 19:59:52 +0200190 if (sm750_dev->fb_count > 1)
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200191 spin_lock(&sm750_dev->slock);
Lorenzo Stoakescb422f32015-03-20 15:22:15 +0000192
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200193 sm750_dev->accel.de_fillrect(&sm750_dev->accel,
194 base, pitch, Bpp,
195 region->dx, region->dy,
196 region->width, region->height,
197 color, rop);
Mike Rapoporta3f92cc2016-01-17 19:59:52 +0200198 if (sm750_dev->fb_count > 1)
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200199 spin_unlock(&sm750_dev->slock);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530200}
201
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100202static void lynxfb_ops_copyarea(struct fb_info *info,
203 const struct fb_copyarea *region)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530204{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100205 struct lynxfb_par *par;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200206 struct sm750_dev *sm750_dev;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100207 unsigned int base, pitch, Bpp;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530208
209 par = info->par;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200210 sm750_dev = par->dev;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530211
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +0530212 /*
213 * each time 2d function begin to work,below three variable always need
214 * be set, seems we can put them together in some place
215 */
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530216 base = par->crtc.oScreen;
217 pitch = info->fix.line_length;
218 Bpp = info->var.bits_per_pixel >> 3;
219
Lorenzo Stoakescb422f32015-03-20 15:22:15 +0000220 /*
221 * If not use spin_lock, system will die if user load driver
Carlos E. Garcia69e98df2015-04-24 09:40:42 -0400222 * and immediately unload driver frequently (dual)
Lorenzo Stoakescb422f32015-03-20 15:22:15 +0000223 */
Mike Rapoporta3f92cc2016-01-17 19:59:52 +0200224 if (sm750_dev->fb_count > 1)
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200225 spin_lock(&sm750_dev->slock);
Lorenzo Stoakescb422f32015-03-20 15:22:15 +0000226
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200227 sm750_dev->accel.de_copyarea(&sm750_dev->accel,
228 base, pitch, region->sx, region->sy,
229 base, pitch, Bpp, region->dx, region->dy,
230 region->width, region->height,
231 HW_ROP2_COPY);
Mike Rapoporta3f92cc2016-01-17 19:59:52 +0200232 if (sm750_dev->fb_count > 1)
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200233 spin_unlock(&sm750_dev->slock);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530234}
235
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100236static void lynxfb_ops_imageblit(struct fb_info *info,
237 const struct fb_image *image)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530238{
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100239 unsigned int base, pitch, Bpp;
240 unsigned int fgcol, bgcol;
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100241 struct lynxfb_par *par;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200242 struct sm750_dev *sm750_dev;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530243
244 par = info->par;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200245 sm750_dev = par->dev;
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +0530246 /*
247 * each time 2d function begin to work,below three variable always need
248 * be set, seems we can put them together in some place
249 */
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530250 base = par->crtc.oScreen;
251 pitch = info->fix.line_length;
252 Bpp = info->var.bits_per_pixel >> 3;
253
Huacai Chen288ef562015-05-11 11:08:22 +0800254 /* TODO: Implement hardware acceleration for image->depth > 1 */
Sudip Mukherjeef8fbc832015-08-07 17:34:05 +0530255 if (image->depth != 1) {
256 cfb_imageblit(info, image);
257 return;
258 }
Huacai Chen288ef562015-05-11 11:08:22 +0800259
Sudip Mukherjeef8fbc832015-08-07 17:34:05 +0530260 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
261 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
262 fgcol = ((u32 *)info->pseudo_palette)[image->fg_color];
263 bgcol = ((u32 *)info->pseudo_palette)[image->bg_color];
264 } else {
265 fgcol = image->fg_color;
266 bgcol = image->bg_color;
267 }
268
Lorenzo Stoakescb422f32015-03-20 15:22:15 +0000269 /*
270 * If not use spin_lock, system will die if user load driver
Carlos E. Garcia69e98df2015-04-24 09:40:42 -0400271 * and immediately unload driver frequently (dual)
Lorenzo Stoakescb422f32015-03-20 15:22:15 +0000272 */
Mike Rapoporta3f92cc2016-01-17 19:59:52 +0200273 if (sm750_dev->fb_count > 1)
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200274 spin_lock(&sm750_dev->slock);
Lorenzo Stoakescb422f32015-03-20 15:22:15 +0000275
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200276 sm750_dev->accel.de_imageblit(&sm750_dev->accel,
277 image->data, image->width >> 3, 0,
278 base, pitch, Bpp,
279 image->dx, image->dy,
280 image->width, image->height,
281 fgcol, bgcol, HW_ROP2_COPY);
Mike Rapoporta3f92cc2016-01-17 19:59:52 +0200282 if (sm750_dev->fb_count > 1)
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200283 spin_unlock(&sm750_dev->slock);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530284}
285
286static int lynxfb_ops_pan_display(struct fb_var_screeninfo *var,
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100287 struct fb_info *info)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530288{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100289 struct lynxfb_par *par;
290 struct lynxfb_crtc *crtc;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530291
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100292 if (!info)
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100293 return -EINVAL;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530294
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100295 par = info->par;
296 crtc = &par->crtc;
Mike Rapoportc202bee2015-10-23 17:55:10 +0300297 return hw_sm750_pan_display(crtc, var, info);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530298}
299
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100300static int lynxfb_ops_set_par(struct fb_info *info)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530301{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100302 struct lynxfb_par *par;
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100303 struct lynxfb_crtc *crtc;
304 struct lynxfb_output *output;
305 struct fb_var_screeninfo *var;
306 struct fb_fix_screeninfo *fix;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530307 int ret;
308 unsigned int line_length;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530309
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100310 if (!info)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530311 return -EINVAL;
312
313 ret = 0;
314 par = info->par;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530315 crtc = &par->crtc;
316 output = &par->output;
317 var = &info->var;
318 fix = &info->fix;
319
Matej Vasekfbb8c962016-01-25 16:02:33 +0100320 /* fix structure is not so FIX ... */
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530321 line_length = var->xres_virtual * var->bits_per_pixel / 8;
Mike Rapoporte3a3f9f2015-10-26 09:05:52 +0200322 line_length = ALIGN(line_length, crtc->line_pad);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530323 fix->line_length = line_length;
Hari Prasath Gujulan Elango78cb7a32015-06-18 12:56:54 +0000324 pr_info("fix->line_length = %d\n", fix->line_length);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530325
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +0530326 /*
327 * var->red,green,blue,transp are need to be set by driver
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530328 * and these data should be set before setcolreg routine
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +0530329 */
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530330
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100331 switch (var->bits_per_pixel) {
Ioana Ciorneid6b0d6d2015-03-11 04:35:04 +0200332 case 8:
333 fix->visual = FB_VISUAL_PSEUDOCOLOR;
334 var->red.offset = 0;
335 var->red.length = 8;
336 var->green.offset = 0;
337 var->green.length = 8;
338 var->blue.offset = 0;
339 var->blue.length = 8;
340 var->transp.length = 0;
341 var->transp.offset = 0;
342 break;
343 case 16:
344 var->red.offset = 11;
345 var->red.length = 5;
346 var->green.offset = 5;
347 var->green.length = 6;
348 var->blue.offset = 0;
349 var->blue.length = 5;
350 var->transp.length = 0;
351 var->transp.offset = 0;
352 fix->visual = FB_VISUAL_TRUECOLOR;
353 break;
354 case 24:
355 case 32:
356 var->red.offset = 16;
357 var->red.length = 8;
358 var->green.offset = 8;
359 var->green.length = 8;
Michel von Czettritza0c838f2015-03-26 23:26:52 +0100360 var->blue.offset = 0;
Ioana Ciorneid6b0d6d2015-03-11 04:35:04 +0200361 var->blue.length = 8;
362 fix->visual = FB_VISUAL_TRUECOLOR;
363 break;
364 default:
365 ret = -EINVAL;
366 break;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530367 }
368 var->height = var->width = -1;
369 var->accel_flags = 0;/*FB_ACCELF_TEXT;*/
370
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100371 if (ret) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530372 pr_err("pixel bpp format not satisfied\n.");
373 return ret;
374 }
Mike Rapoportc202bee2015-10-23 17:55:10 +0300375 ret = hw_sm750_crtc_setMode(crtc, var, fix);
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100376 if (!ret)
Mike Rapoport9821ed042015-10-23 17:55:11 +0300377 ret = hw_sm750_output_setMode(output, var, fix);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530378 return ret;
379}
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530380
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100381static inline unsigned int chan_to_field(unsigned int chan,
382 struct fb_bitfield *bf)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530383{
384 chan &= 0xffff;
385 chan >>= 16 - bf->length;
386 return chan << bf->offset;
387}
388
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530389#ifdef CONFIG_PM
390static int lynxfb_suspend(struct pci_dev *pdev, pm_message_t mesg)
391{
392 struct fb_info *info;
Mike Rapoport083c2042015-10-26 09:06:03 +0200393 struct sm750_dev *sm750_dev;
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530394 int ret;
395
396 if (mesg.event == pdev->dev.power.power_state.event)
397 return 0;
398
399 ret = 0;
Mike Rapoport083c2042015-10-26 09:06:03 +0200400 sm750_dev = pci_get_drvdata(pdev);
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530401 switch (mesg.event) {
402 case PM_EVENT_FREEZE:
403 case PM_EVENT_PRETHAW:
404 pdev->dev.power.power_state = mesg;
405 return 0;
406 }
407
408 console_lock();
409 if (mesg.event & PM_EVENT_SLEEP) {
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200410 info = sm750_dev->fbinfo[0];
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530411 if (info)
Michel von Czettritz4bd95032015-03-26 23:26:04 +0100412 /* 1 means do suspend */
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530413 fb_set_suspend(info, 1);
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200414 info = sm750_dev->fbinfo[1];
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530415 if (info)
Michel von Czettritz4bd95032015-03-26 23:26:04 +0100416 /* 1 means do suspend */
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530417 fb_set_suspend(info, 1);
418
419 ret = pci_save_state(pdev);
420 if (ret) {
Eva Rachel Retuya6504b9b2016-03-06 13:20:21 +0800421 dev_err(&pdev->dev,
422 "error:%d occurred in pci_save_state\n", ret);
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530423 return ret;
424 }
425
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530426 ret = pci_set_power_state(pdev, pci_choose_state(pdev, mesg));
427 if (ret) {
Eva Rachel Retuya6504b9b2016-03-06 13:20:21 +0800428 dev_err(&pdev->dev,
429 "error:%d occurred in pci_set_power_state\n",
430 ret);
Sudip Mukherjee848f2fc2015-03-10 14:15:38 +0530431 return ret;
432 }
433 }
434
435 pdev->dev.power.power_state = mesg;
436 console_unlock();
437 return ret;
438}
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530439
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100440static int lynxfb_resume(struct pci_dev *pdev)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530441{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100442 struct fb_info *info;
Mike Rapoport700591a2015-10-26 09:06:01 +0200443 struct sm750_dev *sm750_dev;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530444
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100445 struct lynxfb_par *par;
446 struct lynxfb_crtc *crtc;
447 struct lynx_cursor *cursor;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530448
449 int ret;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100450
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530451 ret = 0;
Mike Rapoport083c2042015-10-26 09:06:03 +0200452 sm750_dev = pci_get_drvdata(pdev);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530453
454 console_lock();
455
Michel von Czettritz61c507c2015-03-26 23:27:25 +0100456 ret = pci_set_power_state(pdev, PCI_D0);
457 if (ret) {
Eva Rachel Retuya6504b9b2016-03-06 13:20:21 +0800458 dev_err(&pdev->dev,
459 "error:%d occurred in pci_set_power_state\n", ret);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530460 return ret;
461 }
462
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100463 if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530464 pci_restore_state(pdev);
Michel von Czettritz61c507c2015-03-26 23:27:25 +0100465 ret = pci_enable_device(pdev);
466 if (ret) {
Eva Rachel Retuya6504b9b2016-03-06 13:20:21 +0800467 dev_err(&pdev->dev,
468 "error:%d occurred in pci_enable_device\n",
469 ret);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530470 return ret;
471 }
472 pci_set_master(pdev);
473 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530474
Mike Rapoport700591a2015-10-26 09:06:01 +0200475 hw_sm750_inithw(sm750_dev, pdev);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530476
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200477 info = sm750_dev->fbinfo[0];
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530478
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100479 if (info) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530480 par = info->par;
481 crtc = &par->crtc;
482 cursor = &crtc->cursor;
Lorenzo Stoakes3de08a22015-03-20 15:22:11 +0000483 memset_io(cursor->vstart, 0x0, cursor->size);
484 memset_io(crtc->vScreen, 0x0, crtc->vidmem_size);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530485 lynxfb_ops_set_par(info);
486 fb_set_suspend(info, 0);
487 }
488
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200489 info = sm750_dev->fbinfo[1];
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530490
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100491 if (info) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530492 par = info->par;
493 crtc = &par->crtc;
494 cursor = &crtc->cursor;
Lorenzo Stoakes3de08a22015-03-20 15:22:11 +0000495 memset_io(cursor->vstart, 0x0, cursor->size);
496 memset_io(crtc->vScreen, 0x0, crtc->vidmem_size);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530497 lynxfb_ops_set_par(info);
498 fb_set_suspend(info, 0);
499 }
500
Binbin Zhou31557ea2015-10-12 09:48:27 +0800501 pdev->dev.power.power_state.event = PM_EVENT_RESUME;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530502 console_unlock();
503 return ret;
504}
505#endif
506
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100507static int lynxfb_ops_check_var(struct fb_var_screeninfo *var,
508 struct fb_info *info)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530509{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100510 struct lynxfb_par *par;
511 struct lynxfb_crtc *crtc;
512 struct lynxfb_output *output;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530513 resource_size_t request;
514
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530515 par = info->par;
516 crtc = &par->crtc;
517 output = &par->output;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530518
519 pr_debug("check var:%dx%d-%d\n",
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100520 var->xres,
521 var->yres,
522 var->bits_per_pixel);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530523
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100524 switch (var->bits_per_pixel) {
Ioana Ciorneid6b0d6d2015-03-11 04:35:04 +0200525 case 8:
Ioana Ciorneid6b0d6d2015-03-11 04:35:04 +0200526 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
527 var->red.offset = 0;
528 var->red.length = 8;
529 var->green.offset = 0;
530 var->green.length = 8;
531 var->blue.offset = 0;
532 var->blue.length = 8;
533 var->transp.length = 0;
534 var->transp.offset = 0;
535 break;
536 case 16:
537 var->red.offset = 11;
538 var->red.length = 5;
539 var->green.offset = 5;
540 var->green.length = 6;
541 var->blue.offset = 0;
542 var->blue.length = 5;
543 var->transp.length = 0;
544 var->transp.offset = 0;
545 info->fix.visual = FB_VISUAL_TRUECOLOR;
546 break;
547 case 24:
548 case 32:
549 var->red.offset = 16;
550 var->red.length = 8;
551 var->green.offset = 8;
552 var->green.length = 8;
Michel von Czettritza0c838f2015-03-26 23:26:52 +0100553 var->blue.offset = 0;
Ioana Ciorneid6b0d6d2015-03-11 04:35:04 +0200554 var->blue.length = 8;
555 info->fix.visual = FB_VISUAL_TRUECOLOR;
556 break;
557 default:
Mike Rapoport104f4562015-10-01 12:14:02 +0300558 pr_err("bpp %d not supported\n", var->bits_per_pixel);
559 return -EINVAL;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530560 }
561 var->height = var->width = -1;
Michel von Czettritz4bd95032015-03-26 23:26:04 +0100562 var->accel_flags = 0;/* FB_ACCELF_TEXT; */
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530563
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100564 /* check if current fb's video memory big enought to hold the onscreen*/
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530565 request = var->xres_virtual * (var->bits_per_pixel >> 3);
566 /* defaulty crtc->channel go with par->index */
567
Mike Rapoporte3a3f9f2015-10-26 09:05:52 +0200568 request = ALIGN(request, crtc->line_pad);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530569 request = request * var->yres_virtual;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100570 if (crtc->vidmem_size < request) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530571 pr_err("not enough video memory for mode\n");
572 return -ENOMEM;
573 }
574
Mike Rapoportc202bee2015-10-23 17:55:10 +0300575 return hw_sm750_crtc_checkMode(crtc, var);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530576}
577
Michel von Czettritz876e5a72015-03-26 23:26:37 +0100578static int lynxfb_ops_setcolreg(unsigned regno,
579 unsigned red,
580 unsigned green,
581 unsigned blue,
582 unsigned transp,
583 struct fb_info *info)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530584{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100585 struct lynxfb_par *par;
586 struct lynxfb_crtc *crtc;
587 struct fb_var_screeninfo *var;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100588 int ret;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530589
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100590 par = info->par;
591 crtc = &par->crtc;
592 var = &info->var;
593 ret = 0;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530594
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100595 if (regno > 256) {
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100596 pr_err("regno = %d\n", regno);
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100597 return -EINVAL;
598 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530599
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100600 if (info->var.grayscale)
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100601 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530602
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100603 if (var->bits_per_pixel == 8 &&
604 info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100605 red >>= 8;
606 green >>= 8;
607 blue >>= 8;
Mike Rapoportc202bee2015-10-23 17:55:10 +0300608 ret = hw_sm750_setColReg(crtc, regno, red, green, blue);
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100609 goto exit;
610 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530611
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100612 if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 256) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100613 u32 val;
Michel von Czettritz876e5a72015-03-26 23:26:37 +0100614
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100615 if (var->bits_per_pixel == 16 ||
Michel von Czettritz876e5a72015-03-26 23:26:37 +0100616 var->bits_per_pixel == 32 ||
617 var->bits_per_pixel == 24) {
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100618 val = chan_to_field(red, &var->red);
619 val |= chan_to_field(green, &var->green);
620 val |= chan_to_field(blue, &var->blue);
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100621 par->pseudo_palette[regno] = val;
622 goto exit;
623 }
624 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530625
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100626 ret = -EINVAL;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530627
628exit:
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100629 return ret;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530630}
631
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100632static int lynxfb_ops_blank(int blank, struct fb_info *info)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530633{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100634 struct lynxfb_par *par;
635 struct lynxfb_output *output;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100636
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100637 pr_debug("blank = %d.\n", blank);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530638 par = info->par;
639 output = &par->output;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100640 return output->proc_setBLANK(output, blank);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530641}
642
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100643static int sm750fb_set_drv(struct lynxfb_par *par)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530644{
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100645 int ret;
Mike Rapoport5ef2f682015-10-26 09:05:56 +0200646 struct sm750_dev *sm750_dev;
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100647 struct lynxfb_output *output;
648 struct lynxfb_crtc *crtc;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530649
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100650 ret = 0;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530651
Mike Rapoportf11fa2a2015-10-26 09:05:59 +0200652 sm750_dev = par->dev;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100653 output = &par->output;
654 crtc = &par->crtc;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530655
Mike Rapoporta3f92cc2016-01-17 19:59:52 +0200656 crtc->vidmem_size = sm750_dev->vidmem_size;
657 if (sm750_dev->fb_count > 1)
658 crtc->vidmem_size >>= 1;
659
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100660 /* setup crtc and output member */
Mike Rapoport5ef2f682015-10-26 09:05:56 +0200661 sm750_dev->hwCursor = g_hwcursor;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530662
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100663 crtc->line_pad = 16;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100664 crtc->xpanstep = 8;
665 crtc->ypanstep = 1;
666 crtc->ywrapstep = 0;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530667
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200668 output->proc_setBLANK = (sm750_dev->revid == SM750LE_REVISION_ID) ?
Sudip Mukherjee13ef3452015-08-07 17:34:03 +0530669 hw_sm750le_setBLANK : hw_sm750_setBLANK;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100670 /* chip specific phase */
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200671 sm750_dev->accel.de_wait = (sm750_dev->revid == SM750LE_REVISION_ID) ?
672 hw_sm750le_deWait : hw_sm750_deWait;
Mike Rapoport1757d102015-10-26 09:05:57 +0200673 switch (sm750_dev->dataflow) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100674 case sm750_simul_pri:
675 output->paths = sm750_pnc;
676 crtc->channel = sm750_primary;
677 crtc->oScreen = 0;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200678 crtc->vScreen = sm750_dev->pvMem;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100679 pr_info("use simul primary mode\n");
680 break;
681 case sm750_simul_sec:
682 output->paths = sm750_pnc;
683 crtc->channel = sm750_secondary;
684 crtc->oScreen = 0;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200685 crtc->vScreen = sm750_dev->pvMem;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100686 break;
687 case sm750_dual_normal:
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100688 if (par->index == 0) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100689 output->paths = sm750_panel;
690 crtc->channel = sm750_primary;
691 crtc->oScreen = 0;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200692 crtc->vScreen = sm750_dev->pvMem;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100693 } else {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100694 output->paths = sm750_crt;
695 crtc->channel = sm750_secondary;
Michel von Czettritz4bd95032015-03-26 23:26:04 +0100696 /* not consider of padding stuffs for oScreen,need fix */
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200697 crtc->oScreen = (sm750_dev->vidmem_size >> 1);
698 crtc->vScreen = sm750_dev->pvMem + crtc->oScreen;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100699 }
700 break;
701 case sm750_dual_swap:
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100702 if (par->index == 0) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100703 output->paths = sm750_panel;
704 crtc->channel = sm750_secondary;
705 crtc->oScreen = 0;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200706 crtc->vScreen = sm750_dev->pvMem;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100707 } else {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100708 output->paths = sm750_crt;
709 crtc->channel = sm750_primary;
Michel von Czettritz4bd95032015-03-26 23:26:04 +0100710 /* not consider of padding stuffs for oScreen,need fix */
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200711 crtc->oScreen = (sm750_dev->vidmem_size >> 1);
712 crtc->vScreen = sm750_dev->pvMem + crtc->oScreen;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100713 }
714 break;
715 default:
716 ret = -EINVAL;
717 }
718
719 return ret;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530720}
721
Michel von Czettritza0c838f2015-03-26 23:26:52 +0100722static struct fb_ops lynxfb_ops = {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530723 .owner = THIS_MODULE,
724 .fb_check_var = lynxfb_ops_check_var,
725 .fb_set_par = lynxfb_ops_set_par,
726 .fb_setcolreg = lynxfb_ops_setcolreg,
727 .fb_blank = lynxfb_ops_blank,
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530728 .fb_fillrect = cfb_fillrect,
729 .fb_imageblit = cfb_imageblit,
730 .fb_copyarea = cfb_copyarea,
731 /* cursor */
732 .fb_cursor = lynxfb_ops_cursor,
733};
734
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100735static int lynxfb_set_fbinfo(struct fb_info *info, int index)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530736{
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100737 int i;
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100738 struct lynxfb_par *par;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200739 struct sm750_dev *sm750_dev;
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100740 struct lynxfb_crtc *crtc;
741 struct lynxfb_output *output;
742 struct fb_var_screeninfo *var;
743 struct fb_fix_screeninfo *fix;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530744
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100745 const struct fb_videomode *pdb[] = {
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100746 lynx750_ext, NULL, vesa_modes,
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100747 };
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100748 int cdb[] = {ARRAY_SIZE(lynx750_ext), 0, VESA_MODEDB_SIZE};
Michel von Czettritza0c838f2015-03-26 23:26:52 +0100749 static const char *mdb_desc[] = {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100750 "driver prepared modes",
751 "kernel prepared default modedb",
752 "kernel HELPERS prepared vesa_modes",
753 };
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530754
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100755 static const char *fixId[2] = {
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100756 "sm750_fb1", "sm750_fb2",
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100757 };
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530758
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100759 int ret, line_length;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530760
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100761 ret = 0;
762 par = (struct lynxfb_par *)info->par;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200763 sm750_dev = par->dev;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100764 crtc = &par->crtc;
765 output = &par->output;
766 var = &info->var;
767 fix = &info->fix;
768
769 /* set index */
770 par->index = index;
771 output->channel = &crtc->channel;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530772 sm750fb_set_drv(par);
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100773 lynxfb_ops.fb_pan_display = lynxfb_ops_pan_display;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530774
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +0530775 /*
776 * set current cursor variable and proc pointer,
777 * must be set after crtc member initialized
778 */
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100779 crtc->cursor.offset = crtc->oScreen + crtc->vidmem_size - 1024;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200780 crtc->cursor.mmio = sm750_dev->pvReg +
781 0x800f0 + (int)crtc->channel * 0x140;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530782
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100783 pr_info("crtc->cursor.mmio = %p\n", crtc->cursor.mmio);
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100784 crtc->cursor.maxH = crtc->cursor.maxW = 64;
Sudip Mukherjee13ef3452015-08-07 17:34:03 +0530785 crtc->cursor.size = crtc->cursor.maxH * crtc->cursor.maxW * 2 / 8;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200786 crtc->cursor.vstart = sm750_dev->pvMem + crtc->cursor.offset;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530787
Mike Rapoport52e93322015-10-26 09:06:04 +0200788 memset_io(crtc->cursor.vstart, 0, crtc->cursor.size);
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100789 if (!g_hwcursor) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100790 lynxfb_ops.fb_cursor = NULL;
Mike Rapoportfb7f4052015-10-26 09:05:50 +0200791 hw_cursor_disable(&crtc->cursor);
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100792 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530793
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100794 /* set info->fbops, must be set before fb_find_mode */
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200795 if (!sm750_dev->accel_off) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100796 /* use 2d acceleration */
797 lynxfb_ops.fb_fillrect = lynxfb_ops_fillrect;
798 lynxfb_ops.fb_copyarea = lynxfb_ops_copyarea;
799 lynxfb_ops.fb_imageblit = lynxfb_ops_imageblit;
800 }
801 info->fbops = &lynxfb_ops;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530802
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100803 if (!g_fbmode[index]) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100804 g_fbmode[index] = g_def_fbmode;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100805 if (index)
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100806 g_fbmode[index] = g_fbmode[0];
807 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530808
Michel von Czettritza0c838f2015-03-26 23:26:52 +0100809 for (i = 0; i < 3; i++) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530810
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100811 ret = fb_find_mode(var, info, g_fbmode[index],
812 pdb[i], cdb[i], NULL, 8);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530813
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100814 if (ret == 1) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530815 pr_info("success! use specified mode:%s in %s\n",
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100816 g_fbmode[index],
817 mdb_desc[i]);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530818 break;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100819 } else if (ret == 2) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530820 pr_warn("use specified mode:%s in %s,with an ignored refresh rate\n",
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100821 g_fbmode[index],
822 mdb_desc[i]);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530823 break;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100824 } else if (ret == 3) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530825 pr_warn("wanna use default mode\n");
Michel von Czettritz4bd95032015-03-26 23:26:04 +0100826 /*break;*/
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100827 } else if (ret == 4) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530828 pr_warn("fall back to any valid mode\n");
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100829 } else {
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100830 pr_warn("ret = %d,fb_find_mode failed,with %s\n",
831 ret,
832 mdb_desc[i]);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530833 }
834 }
835
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100836 /* some member of info->var had been set by fb_find_mode */
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530837
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100838 pr_info("Member of info->var is :\n\
Michel von Czettritz3318bb52015-03-26 23:26:23 +0100839 xres=%d\n\
840 yres=%d\n\
841 xres_virtual=%d\n\
842 yres_virtual=%d\n\
843 xoffset=%d\n\
844 yoffset=%d\n\
845 bits_per_pixel=%d\n \
846 ...\n",
847 var->xres,
848 var->yres,
849 var->xres_virtual,
850 var->yres_virtual,
851 var->xoffset,
852 var->yoffset,
853 var->bits_per_pixel);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530854
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100855 /* set par */
856 par->info = info;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530857
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100858 /* set info */
Mike Rapoporte3a3f9f2015-10-26 09:05:52 +0200859 line_length = ALIGN((var->xres_virtual * var->bits_per_pixel / 8),
860 crtc->line_pad);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530861
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100862 info->pseudo_palette = &par->pseudo_palette[0];
863 info->screen_base = crtc->vScreen;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100864 pr_debug("screen_base vaddr = %p\n", info->screen_base);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530865 info->screen_size = line_length * var->yres_virtual;
Sudip Mukherjee13ef3452015-08-07 17:34:03 +0530866 info->flags = FBINFO_FLAG_DEFAULT | 0;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530867
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100868 /* set info->fix */
869 fix->type = FB_TYPE_PACKED_PIXELS;
870 fix->type_aux = 0;
871 fix->xpanstep = crtc->xpanstep;
872 fix->ypanstep = crtc->ypanstep;
873 fix->ywrapstep = crtc->ywrapstep;
874 fix->accel = FB_ACCEL_SMI;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530875
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100876 strlcpy(fix->id, fixId[index], sizeof(fix->id));
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530877
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200878 fix->smem_start = crtc->oScreen + sm750_dev->vidmem_start;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100879 pr_info("fix->smem_start = %lx\n", fix->smem_start);
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +0530880 /*
881 * according to mmap experiment from user space application,
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100882 * fix->mmio_len should not larger than virtual size
883 * (xres_virtual x yres_virtual x ByPP)
884 * Below line maybe buggy when user mmap fb dev node and write
885 * data into the bound over virtual size
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +0530886 */
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100887 fix->smem_len = crtc->vidmem_size;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100888 pr_info("fix->smem_len = %x\n", fix->smem_len);
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100889 info->screen_size = fix->smem_len;
890 fix->line_length = line_length;
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200891 fix->mmio_start = sm750_dev->vidreg_start;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100892 pr_info("fix->mmio_start = %lx\n", fix->mmio_start);
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200893 fix->mmio_len = sm750_dev->vidreg_size;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100894 pr_info("fix->mmio_len = %x\n", fix->mmio_len);
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100895 switch (var->bits_per_pixel) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100896 case 8:
897 fix->visual = FB_VISUAL_PSEUDOCOLOR;
898 break;
899 case 16:
900 case 32:
901 fix->visual = FB_VISUAL_TRUECOLOR;
902 break;
903 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530904
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100905 /* set var */
906 var->activate = FB_ACTIVATE_NOW;
907 var->accel_flags = 0;
908 var->vmode = FB_VMODE_NONINTERLACED;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530909
Juston Lia1fe1542015-07-14 21:14:44 -0700910 pr_debug("#1 show info->cmap :\nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100911 info->cmap.start, info->cmap.len,
912 info->cmap.red, info->cmap.green, info->cmap.blue,
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100913 info->cmap.transp);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530914
Michel von Czettritz61c507c2015-03-26 23:27:25 +0100915 ret = fb_alloc_cmap(&info->cmap, 256, 0);
916 if (ret < 0) {
Masanari Iida00827202015-05-28 08:41:16 +0900917 pr_err("Could not allocate memory for cmap.\n");
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100918 goto exit;
919 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530920
Michel von Czettritza0c838f2015-03-26 23:26:52 +0100921 pr_debug("#2 show info->cmap :\nstart=%d,len=%d,red=%p,green=%p,blue=%p,transp=%p\n",
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100922 info->cmap.start, info->cmap.len,
923 info->cmap.red, info->cmap.green, info->cmap.blue,
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100924 info->cmap.transp);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530925
926exit:
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100927 lynxfb_ops_check_var(var, info);
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100928 return ret;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530929}
930
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100931/* chip specific g_option configuration routine */
Mike Rapoport700591a2015-10-26 09:06:01 +0200932static void sm750fb_setup(struct sm750_dev *sm750_dev, char *src)
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530933{
Michel von Czettritz27fa1592015-03-26 23:25:37 +0100934 char *opt;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530935 int swap;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100936
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100937 swap = 0;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530938
Mike Rapoport1757d102015-10-26 09:05:57 +0200939 sm750_dev->initParm.chip_clk = 0;
940 sm750_dev->initParm.mem_clk = 0;
941 sm750_dev->initParm.master_clk = 0;
942 sm750_dev->initParm.powerMode = 0;
943 sm750_dev->initParm.setAllEngOff = 0;
944 sm750_dev->initParm.resetMemory = 1;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530945
Michel von Czettritz4bd95032015-03-26 23:26:04 +0100946 /* defaultly turn g_hwcursor on for both view */
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100947 g_hwcursor = 3;
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530948
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100949 if (!src || !*src) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100950 pr_warn("no specific g_option.\n");
951 goto NO_PARAM;
952 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530953
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100954 while ((opt = strsep(&src, ":")) != NULL && *opt != 0) {
Hari Prasath Gujulan Elango78cb7a32015-06-18 12:56:54 +0000955 pr_info("opt=%s\n", opt);
956 pr_info("src=%s\n", src);
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530957
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100958 if (!strncmp(opt, "swap", strlen("swap")))
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100959 swap = 1;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100960 else if (!strncmp(opt, "nocrt", strlen("nocrt")))
Mike Rapoport1757d102015-10-26 09:05:57 +0200961 sm750_dev->nocrt = 1;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100962 else if (!strncmp(opt, "36bit", strlen("36bit")))
Mike Rapoport1757d102015-10-26 09:05:57 +0200963 sm750_dev->pnltype = sm750_doubleTFT;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100964 else if (!strncmp(opt, "18bit", strlen("18bit")))
Mike Rapoport1757d102015-10-26 09:05:57 +0200965 sm750_dev->pnltype = sm750_dualTFT;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100966 else if (!strncmp(opt, "24bit", strlen("24bit")))
Mike Rapoport1757d102015-10-26 09:05:57 +0200967 sm750_dev->pnltype = sm750_24TFT;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100968 else if (!strncmp(opt, "nohwc0", strlen("nohwc0")))
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100969 g_hwcursor &= ~0x1;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100970 else if (!strncmp(opt, "nohwc1", strlen("nohwc1")))
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100971 g_hwcursor &= ~0x2;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100972 else if (!strncmp(opt, "nohwc", strlen("nohwc")))
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100973 g_hwcursor = 0;
Michel von Czettritz70407df2015-03-26 23:25:08 +0100974 else {
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100975 if (!g_fbmode[0]) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100976 g_fbmode[0] = opt;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100977 pr_info("find fbmode0 : %s\n", g_fbmode[0]);
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100978 } else if (!g_fbmode[1]) {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100979 g_fbmode[1] = opt;
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +0100980 pr_info("find fbmode1 : %s\n", g_fbmode[1]);
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100981 } else {
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100982 pr_warn("How many view you wann set?\n");
983 }
984 }
985 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +0530986
987NO_PARAM:
Mike Rapoporte359b6a2015-10-26 09:06:06 +0200988 if (sm750_dev->revid != SM750LE_REVISION_ID) {
Mike Rapoporta3f92cc2016-01-17 19:59:52 +0200989 if (sm750_dev->fb_count > 1) {
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100990 if (swap)
Mike Rapoport1757d102015-10-26 09:05:57 +0200991 sm750_dev->dataflow = sm750_dual_swap;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100992 else
Mike Rapoport1757d102015-10-26 09:05:57 +0200993 sm750_dev->dataflow = sm750_dual_normal;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +0100994 } else {
995 if (swap)
Mike Rapoport1757d102015-10-26 09:05:57 +0200996 sm750_dev->dataflow = sm750_simul_sec;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100997 else
Mike Rapoport1757d102015-10-26 09:05:57 +0200998 sm750_dev->dataflow = sm750_simul_pri;
Michel von Czettritzc52c3702015-03-26 23:24:32 +0100999 }
Michel von Czettritz5ace4e12015-03-26 23:25:22 +01001000 } else {
Michel von Czettritzc52c3702015-03-26 23:24:32 +01001001 /* SM750LE only have one crt channel */
Mike Rapoport1757d102015-10-26 09:05:57 +02001002 sm750_dev->dataflow = sm750_simul_sec;
Michel von Czettritz4bd95032015-03-26 23:26:04 +01001003 /* sm750le do not have complex attributes */
Mike Rapoport1757d102015-10-26 09:05:57 +02001004 sm750_dev->nocrt = 0;
Michel von Czettritzc52c3702015-03-26 23:24:32 +01001005 }
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301006}
1007
Mike Rapoport9324f912016-01-17 19:59:53 +02001008static void sm750fb_frambuffer_release(struct sm750_dev *sm750_dev)
1009{
1010 struct fb_info *fb_info;
1011
1012 while (sm750_dev->fb_count) {
1013 fb_info = sm750_dev->fbinfo[sm750_dev->fb_count - 1];
1014 unregister_framebuffer(fb_info);
1015 framebuffer_release(fb_info);
1016 sm750_dev->fb_count--;
1017 }
1018}
1019
Mike Rapoporta50bc322016-01-17 19:59:54 +02001020static int sm750fb_frambuffer_alloc(struct sm750_dev *sm750_dev, int fbidx)
1021{
1022 struct fb_info *fb_info;
1023 struct lynxfb_par *par;
1024 int err;
1025
1026 fb_info = framebuffer_alloc(sizeof(struct lynxfb_par),
1027 &sm750_dev->pdev->dev);
1028 if (!fb_info)
1029 return -ENOMEM;
1030
1031 sm750_dev->fbinfo[fbidx] = fb_info;
1032 par = fb_info->par;
1033 par->dev = sm750_dev;
1034
1035 err = lynxfb_set_fbinfo(fb_info, fbidx);
1036 if (err)
1037 goto release_fb;
1038
1039 err = register_framebuffer(fb_info);
1040 if (err < 0)
1041 goto release_fb;
1042
1043 sm750_dev->fb_count++;
1044
1045 return 0;
1046
1047release_fb:
1048 framebuffer_release(fb_info);
1049 return err;
1050}
1051
Michel von Czettritz27fa1592015-03-26 23:25:37 +01001052static int lynxfb_pci_probe(struct pci_dev *pdev,
Greg Donaldeb0f4272015-06-18 15:06:56 -05001053 const struct pci_device_id *ent)
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301054{
Mike Rapoport5ef2f682015-10-26 09:05:56 +02001055 struct sm750_dev *sm750_dev = NULL;
Mike Rapoporta50bc322016-01-17 19:59:54 +02001056 int max_fb;
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301057 int fbidx;
Mike Rapoportbaf24532016-01-17 19:59:50 +02001058 int err;
Michel von Czettritzc52c3702015-03-26 23:24:32 +01001059
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301060 /* enable device */
Amitoj Kaur Chawla13b79a02016-02-28 21:22:00 +05301061 err = pcim_enable_device(pdev);
Mike Rapoportbaf24532016-01-17 19:59:50 +02001062 if (err)
1063 return err;
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301064
Mike Rapoportbaf24532016-01-17 19:59:50 +02001065 err = -ENOMEM;
Amitoj Kaur Chawla677c5072016-02-28 21:21:53 +05301066 sm750_dev = devm_kzalloc(&pdev->dev, sizeof(*sm750_dev), GFP_KERNEL);
Mike Rapoportbaf24532016-01-17 19:59:50 +02001067 if (!sm750_dev)
Amitoj Kaur Chawla13b79a02016-02-28 21:22:00 +05301068 return err;
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301069
Mike Rapoporte359b6a2015-10-26 09:06:06 +02001070 sm750_dev->fbinfo[0] = sm750_dev->fbinfo[1] = NULL;
1071 sm750_dev->devid = pdev->device;
1072 sm750_dev->revid = pdev->revision;
Mike Rapoporte359b6a2015-10-26 09:06:06 +02001073 sm750_dev->pdev = pdev;
1074 sm750_dev->mtrr_off = g_nomtrr;
1075 sm750_dev->mtrr.vram = 0;
1076 sm750_dev->accel_off = g_noaccel;
Mike Rapoporte359b6a2015-10-26 09:06:06 +02001077 spin_lock_init(&sm750_dev->slock);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301078
Mike Rapoporte359b6a2015-10-26 09:06:06 +02001079 if (!sm750_dev->accel_off) {
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +05301080 /*
1081 * hook deInit and 2d routines, notes that below hw_xxx
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301082 * routine can work on most of lynx chips
Michel von Czettritz3318bb52015-03-26 23:26:23 +01001083 * if some chip need specific function,
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +05301084 * please hook it in smXXX_set_drv routine
1085 */
Mike Rapoporte359b6a2015-10-26 09:06:06 +02001086 sm750_dev->accel.de_init = hw_de_init;
1087 sm750_dev->accel.de_fillrect = hw_fillrect;
1088 sm750_dev->accel.de_copyarea = hw_copyarea;
1089 sm750_dev->accel.de_imageblit = hw_imageblit;
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301090 }
1091
1092 /* call chip specific setup routine */
Mike Rapoport700591a2015-10-26 09:06:01 +02001093 sm750fb_setup(sm750_dev, g_settings);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301094
1095 /* call chip specific mmap routine */
Mike Rapoportbaf24532016-01-17 19:59:50 +02001096 err = hw_sm750_map(sm750_dev, pdev);
1097 if (err)
Amitoj Kaur Chawla677c5072016-02-28 21:21:53 +05301098 return err;
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301099
Mike Rapoporte359b6a2015-10-26 09:06:06 +02001100 if (!sm750_dev->mtrr_off)
1101 sm750_dev->mtrr.vram = arch_phys_wc_add(sm750_dev->vidmem_start,
1102 sm750_dev->vidmem_size);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301103
Mike Rapoporte359b6a2015-10-26 09:06:06 +02001104 memset_io(sm750_dev->pvMem, 0, sm750_dev->vidmem_size);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301105
Mike Rapoport083c2042015-10-26 09:06:03 +02001106 pci_set_drvdata(pdev, sm750_dev);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301107
1108 /* call chipInit routine */
Mike Rapoport700591a2015-10-26 09:06:01 +02001109 hw_sm750_inithw(sm750_dev, pdev);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301110
Mike Rapoporta50bc322016-01-17 19:59:54 +02001111 /* allocate frame buffer info structures according to g_dualview */
1112 max_fb = g_dualview ? 2 : 1;
1113 for (fbidx = 0; fbidx < max_fb; fbidx++) {
1114 err = sm750fb_frambuffer_alloc(sm750_dev, fbidx);
1115 if (err)
1116 goto release_fb;
Michel von Czettritzc52c3702015-03-26 23:24:32 +01001117 }
1118
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301119 return 0;
1120
Mike Rapoporta50bc322016-01-17 19:59:54 +02001121release_fb:
1122 sm750fb_frambuffer_release(sm750_dev);
Mike Rapoportbaf24532016-01-17 19:59:50 +02001123 return err;
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301124}
1125
Arnd Bergmannbb6ce8b2015-04-11 00:03:19 +02001126static void lynxfb_pci_remove(struct pci_dev *pdev)
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301127{
Mike Rapoport4fd92f52015-10-26 09:06:02 +02001128 struct sm750_dev *sm750_dev;
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301129
Mike Rapoport083c2042015-10-26 09:06:03 +02001130 sm750_dev = pci_get_drvdata(pdev);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301131
Mike Rapoport9324f912016-01-17 19:59:53 +02001132 sm750fb_frambuffer_release(sm750_dev);
Mike Rapoporte359b6a2015-10-26 09:06:06 +02001133 arch_phys_wc_del(sm750_dev->mtrr.vram);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301134
Mike Rapoporte359b6a2015-10-26 09:06:06 +02001135 iounmap(sm750_dev->pvReg);
1136 iounmap(sm750_dev->pvMem);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301137 kfree(g_settings);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301138}
1139
Michel von Czettritz27fa1592015-03-26 23:25:37 +01001140static int __init lynxfb_setup(char *options)
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301141{
1142 int len;
Michel von Czettritz27fa1592015-03-26 23:25:37 +01001143 char *opt, *tmp;
Michel von Czettritzc52c3702015-03-26 23:24:32 +01001144
Michel von Czettritz5ace4e12015-03-26 23:25:22 +01001145 if (!options || !*options) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301146 pr_warn("no options.\n");
1147 return 0;
1148 }
1149
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +01001150 pr_info("options:%s\n", options);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301151
1152 len = strlen(options) + 1;
Madhusudhanan Ravindrana99e3342015-03-10 23:07:39 +05301153 g_settings = kzalloc(len, GFP_KERNEL);
Michel von Czettritz5ace4e12015-03-26 23:25:22 +01001154 if (!g_settings)
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301155 return -ENOMEM;
1156
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301157 tmp = g_settings;
1158
Sudip Mukherjeed11ac7c2015-08-07 17:34:04 +05301159 /*
1160 * Notes:
1161 * char * strsep(char **s,const char * ct);
1162 * @s: the string to be searched
1163 * @ct :the characters to search for
1164 *
1165 * strsep() updates @options to pointer after the first found token
1166 * it also returns the pointer ahead the token.
1167 */
Michel von Czettritza0c838f2015-03-26 23:26:52 +01001168 while ((opt = strsep(&options, ":")) != NULL) {
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301169 /* options that mean for any lynx chips are configured here */
Michel von Czettritz5ace4e12015-03-26 23:25:22 +01001170 if (!strncmp(opt, "noaccel", strlen("noaccel")))
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301171 g_noaccel = 1;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +01001172 else if (!strncmp(opt, "nomtrr", strlen("nomtrr")))
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301173 g_nomtrr = 1;
Michel von Czettritz5ace4e12015-03-26 23:25:22 +01001174 else if (!strncmp(opt, "dual", strlen("dual")))
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301175 g_dualview = 1;
Michel von Czettritz70407df2015-03-26 23:25:08 +01001176 else {
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +01001177 strcat(tmp, opt);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301178 tmp += strlen(opt);
Michel von Czettritz5ace4e12015-03-26 23:25:22 +01001179 if (options != NULL)
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301180 *tmp++ = ':';
1181 else
1182 *tmp++ = 0;
1183 }
1184 }
1185
1186 /* misc g_settings are transport to chip specific routines */
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +01001187 pr_info("parameter left for chip specific analysis:%s\n", g_settings);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301188 return 0;
1189}
1190
1191static struct pci_device_id smi_pci_table[] = {
1192 { PCI_DEVICE(0x126f, 0x0750), },
1193 {0,}
1194};
1195
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +01001196MODULE_DEVICE_TABLE(pci, smi_pci_table);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301197
1198static struct pci_driver lynxfb_driver = {
1199 .name = "sm750fb",
1200 .id_table = smi_pci_table,
1201 .probe = lynxfb_pci_probe,
1202 .remove = lynxfb_pci_remove,
1203#ifdef CONFIG_PM
1204 .suspend = lynxfb_suspend,
1205 .resume = lynxfb_resume,
1206#endif
1207};
1208
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301209static int __init lynxfb_init(void)
1210{
Michel von Czettritza0c838f2015-03-26 23:26:52 +01001211 char *option;
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301212 int ret;
1213
1214#ifdef MODULE
1215 option = g_option;
1216#else
Michel von Czettritz5ace4e12015-03-26 23:25:22 +01001217 if (fb_get_options("sm750fb", &option))
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301218 return -ENODEV;
1219#endif
1220
1221 lynxfb_setup(option);
1222 ret = pci_register_driver(&lynxfb_driver);
1223 return ret;
1224}
1225module_init(lynxfb_init);
1226
1227static void __exit lynxfb_exit(void)
1228{
1229 pci_unregister_driver(&lynxfb_driver);
1230}
1231module_exit(lynxfb_exit);
1232
Michel von Czettritz45e3b3d2015-03-26 23:24:53 +01001233module_param(g_option, charp, S_IRUGO);
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301234
1235MODULE_PARM_DESC(g_option,
Michel von Czettritzc52c3702015-03-26 23:24:32 +01001236 "\n\t\tCommon options:\n"
1237 "\t\tnoaccel:disable 2d capabilities\n"
1238 "\t\tnomtrr:disable MTRR attribute for video memory\n"
1239 "\t\tdualview:dual frame buffer feature enabled\n"
1240 "\t\tnohwc:disable hardware cursor\n"
1241 "\t\tUsual example:\n"
1242 "\t\tinsmod ./sm750fb.ko g_option=\"noaccel,nohwc,1280x1024-8@60\"\n"
1243 );
Sudip Mukherjee81dee672015-03-03 16:21:06 +05301244
1245MODULE_AUTHOR("monk liu <monk.liu@siliconmotion.com>");
1246MODULE_AUTHOR("Sudip Mukherjee <sudip@vectorindia.org>");
1247MODULE_DESCRIPTION("Frame buffer driver for SM750 chipset");
1248MODULE_LICENSE("GPL v2");