40,6 → 40,16 |
|
static LIST_HEAD(kernel_fb_helper_list); |
|
int drm_fb_helper_add_connector(struct drm_connector *connector) |
{ |
connector->fb_helper_private = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); |
if (!connector->fb_helper_private) |
return -ENOMEM; |
|
return 0; |
} |
EXPORT_SYMBOL(drm_fb_helper_add_connector); |
|
bool drm_fb_helper_force_kernel_mode(void) |
{ |
int i = 0; |
230,6 → 240,96 |
} |
EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); |
|
static void setcolreg(struct drm_crtc *crtc, u16 red, u16 green, |
u16 blue, u16 regno, struct fb_info *info) |
{ |
struct drm_fb_helper *fb_helper = info->par; |
struct drm_framebuffer *fb = fb_helper->fb; |
int pindex; |
|
pindex = regno; |
|
if (fb->bits_per_pixel == 16) { |
pindex = regno << 3; |
|
if (fb->depth == 16 && regno > 63) |
return; |
if (fb->depth == 15 && regno > 31) |
return; |
|
if (fb->depth == 16) { |
u16 r, g, b; |
int i; |
if (regno < 32) { |
for (i = 0; i < 8; i++) |
fb_helper->funcs->gamma_set(crtc, red, |
green, blue, pindex + i); |
} |
|
fb_helper->funcs->gamma_get(crtc, &r, |
&g, &b, |
pindex >> 1); |
|
for (i = 0; i < 4; i++) |
fb_helper->funcs->gamma_set(crtc, r, |
green, b, |
(pindex >> 1) + i); |
} |
} |
|
if (fb->depth != 16) |
fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex); |
|
if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { |
((u32 *) fb->pseudo_palette)[regno] = |
(regno << info->var.red.offset) | |
(regno << info->var.green.offset) | |
(regno << info->var.blue.offset); |
} |
} |
|
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) |
{ |
struct drm_fb_helper *fb_helper = info->par; |
struct drm_device *dev = fb_helper->dev; |
u16 *red, *green, *blue, *transp; |
struct drm_crtc *crtc; |
int i, rc = 0; |
int start; |
|
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
for (i = 0; i < fb_helper->crtc_count; i++) { |
if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) |
break; |
} |
if (i == fb_helper->crtc_count) |
continue; |
|
red = cmap->red; |
green = cmap->green; |
blue = cmap->blue; |
transp = cmap->transp; |
start = cmap->start; |
|
for (i = 0; i < cmap->len; i++) { |
u16 hred, hgreen, hblue, htransp = 0xffff; |
|
hred = *red++; |
hgreen = *green++; |
hblue = *blue++; |
|
if (transp) |
htransp = *transp++; |
|
setcolreg(crtc, hred, hgreen, hblue, start++, info); |
} |
crtc_funcs->load_lut(crtc); |
} |
return rc; |
} |
EXPORT_SYMBOL(drm_fb_helper_setcmap); |
|
int drm_fb_helper_setcolreg(unsigned regno, |
unsigned red, |
unsigned green, |
242,9 → 342,11 |
struct drm_crtc *crtc; |
int i; |
|
if (regno > 255) |
return 1; |
|
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
struct drm_framebuffer *fb = fb_helper->fb; |
|
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; |
for (i = 0; i < fb_helper->crtc_count; i++) { |
if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) |
break; |
252,36 → 354,10 |
if (i == fb_helper->crtc_count) |
continue; |
|
if (regno > 255) |
return 1; |
|
if (fb->depth == 8) { |
fb_helper->funcs->gamma_set(crtc, red, green, blue, regno); |
return 0; |
setcolreg(crtc, red, green, blue, regno, info); |
crtc_funcs->load_lut(crtc); |
} |
|
if (regno < 16) { |
switch (fb->depth) { |
case 15: |
fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | |
((green & 0xf800) >> 6) | |
((blue & 0xf800) >> 11); |
break; |
case 16: |
fb->pseudo_palette[regno] = (red & 0xf800) | |
((green & 0xfc00) >> 5) | |
((blue & 0xf800) >> 11); |
break; |
case 24: |
case 32: |
fb->pseudo_palette[regno] = |
(((red >> 8) & 0xff) << info->var.red.offset) | |
(((green >> 8) & 0xff) << info->var.green.offset) | |
(((blue >> 8) & 0xff) << info->var.blue.offset); |
break; |
} |
} |
} |
return 0; |
} |
EXPORT_SYMBOL(drm_fb_helper_setcolreg); |
450,11 → 526,14 |
EXPORT_SYMBOL(drm_fb_helper_pan_display); |
|
int drm_fb_helper_single_fb_probe(struct drm_device *dev, |
int preferred_bpp, |
int (*fb_create)(struct drm_device *dev, |
uint32_t fb_width, |
uint32_t fb_height, |
uint32_t surface_width, |
uint32_t surface_height, |
uint32_t surface_depth, |
uint32_t surface_bpp, |
struct drm_framebuffer **fb_ptr)) |
{ |
struct drm_crtc *crtc; |
468,8 → 547,48 |
struct drm_framebuffer *fb; |
struct drm_mode_set *modeset = NULL; |
struct drm_fb_helper *fb_helper; |
uint32_t surface_depth = 24, surface_bpp = 32; |
|
/* if driver picks 8 or 16 by default use that |
for both depth/bpp */ |
if (preferred_bpp != surface_bpp) { |
surface_depth = surface_bpp = preferred_bpp; |
} |
/* first up get a count of crtcs now in use and new min/maxes width/heights */ |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; |
|
struct drm_fb_helper_cmdline_mode *cmdline_mode; |
|
if (!fb_help_conn) |
continue; |
|
cmdline_mode = &fb_help_conn->cmdline_mode; |
|
if (cmdline_mode->bpp_specified) { |
switch (cmdline_mode->bpp) { |
case 8: |
surface_depth = surface_bpp = 8; |
break; |
case 15: |
surface_depth = 15; |
surface_bpp = 16; |
break; |
case 16: |
surface_depth = surface_bpp = 16; |
break; |
case 24: |
surface_depth = surface_bpp = 24; |
break; |
case 32: |
surface_depth = 24; |
surface_bpp = 32; |
break; |
} |
break; |
} |
} |
|
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
if (drm_helper_crtc_in_use(crtc)) { |
if (crtc->desired_mode) { |
498,7 → 617,8 |
/* do we have an fb already? */ |
if (list_empty(&dev->mode_config.fb_kernel_list)) { |
ret = (*fb_create)(dev, fb_width, fb_height, surface_width, |
surface_height, &fb); |
surface_height, surface_depth, surface_bpp, |
&fb); |
if (ret) |
return -EINVAL; |
new_fb = 1; |
577,10 → 697,12 |
} |
EXPORT_SYMBOL(drm_fb_helper_free); |
|
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch) |
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, |
uint32_t depth) |
{ |
info->fix.type = FB_TYPE_PACKED_PIXELS; |
info->fix.visual = FB_VISUAL_TRUECOLOR; |
info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR : |
FB_VISUAL_DIRECTCOLOR; |
info->fix.type_aux = 0; |
info->fix.xpanstep = 1; /* doing it in hw */ |
info->fix.ypanstep = 1; /* doing it in hw */ |