/* * It's common for several clients to have framebuffer open simultaneously. * e.g. both fbcon and X. Makes things interesting. * Assumes caller is holding info->lock (for open and release at least) */ static int udl_fb_open(struct fb_info *info, int user) { struct udl_fbdev *ufbdev = info->par; struct drm_device *dev = ufbdev->ufb.base.dev; struct udl_device *udl = dev->dev_private; /* If the USB device is gone, we don't accept new opens */ if (drm_device_is_unplugged(udl->ddev)) return -ENODEV; ufbdev->fb_count++; #ifdef CONFIG_DRM_FBDEV_EMULATION if (fb_defio && (info->fbdefio == NULL)) { /* enable defio at last moment if not disabled by client */ struct fb_deferred_io *fbdefio; fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); if (fbdefio) { fbdefio->delay = DL_DEFIO_WRITE_DELAY; fbdefio->deferred_io = drm_fb_helper_deferred_io; } info->fbdefio = fbdefio; fb_deferred_io_init(info); } #endif pr_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n", info->node, user, info, ufbdev->fb_count); return 0; }
static int hecubafb_probe(struct platform_device *dev) { struct fb_info *info; struct hecuba_board *board; int retval = -ENOMEM; int videomemorysize; unsigned char *videomemory; struct hecubafb_par *par; /* pick up board specific routines */ board = dev->dev.platform_data; if (!board) return -EINVAL; /* try to count device specific driver, if can't, platform recalls */ if (!try_module_get(board->owner)) return -ENODEV; videomemorysize = (DPY_W*DPY_H)/8; videomemory = vzalloc(videomemorysize); if (!videomemory) goto err_videomem_alloc; info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev); if (!info) goto err_fballoc; info->screen_base = (char __force __iomem *)videomemory; info->fbops = &hecubafb_ops; info->var = hecubafb_var; info->fix = hecubafb_fix; info->fix.smem_len = videomemorysize; par = info->par; par->info = info; par->board = board; par->send_command = apollo_send_command; par->send_data = apollo_send_data; info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; info->fbdefio = &hecubafb_defio; fb_deferred_io_init(info); retval = register_framebuffer(info); if (retval < 0) goto err_fbreg; platform_set_drvdata(dev, info); printk(KERN_INFO "fb%d: Hecuba frame buffer device, using %dK of video memory\n", info->node, videomemorysize >> 10); /* this inits the dpy */ retval = par->board->init(par); if (retval < 0) goto err_fbreg; return 0; err_fbreg: framebuffer_release(info); err_fballoc: vfree(videomemory); err_videomem_alloc: module_put(board->owner); return retval; }
static int qxlfb_create(struct qxl_fbdev *qfbdev, struct drm_fb_helper_surface_size *sizes) { struct qxl_device *qdev = qfbdev->qdev; struct fb_info *info; struct drm_framebuffer *fb = NULL; struct drm_mode_fb_cmd2 mode_cmd; struct drm_gem_object *gobj = NULL; struct qxl_bo *qbo = NULL; int ret; int size; int bpp = sizes->surface_bpp; int depth = sizes->surface_depth; void *shadow; mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 1) / 8), 64); mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); ret = qxlfb_create_pinned_object(qfbdev, &mode_cmd, &gobj); if (ret < 0) return ret; qbo = gem_to_qxl_bo(gobj); QXL_INFO(qdev, "%s: %dx%d %d\n", __func__, mode_cmd.width, mode_cmd.height, mode_cmd.pitches[0]); shadow = vmalloc(mode_cmd.pitches[0] * mode_cmd.height); /* TODO: what's the usual response to memory allocation errors? */ BUG_ON(!shadow); QXL_INFO(qdev, "surface0 at gpu offset %lld, mmap_offset %lld (virt %p, shadow %p)\n", qxl_bo_gpu_offset(qbo), qxl_bo_mmap_offset(qbo), qbo->kptr, shadow); size = mode_cmd.pitches[0] * mode_cmd.height; info = drm_fb_helper_alloc_fbi(&qfbdev->helper); if (IS_ERR(info)) { ret = PTR_ERR(info); goto out_unref; } info->par = qfbdev; qxl_framebuffer_init(qdev->ddev, &qfbdev->qfb, &mode_cmd, gobj, &qxlfb_fb_funcs); fb = &qfbdev->qfb.base; /* setup helper with fb data */ qfbdev->helper.fb = fb; qfbdev->shadow = shadow; strcpy(info->fix.id, "qxldrmfb"); drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; info->fbops = &qxlfb_ops; /* * TODO: using gobj->size in various places in this function. Not sure * what the difference between the different sizes is. */ info->fix.smem_start = qdev->vram_base; /* TODO - correct? */ info->fix.smem_len = gobj->size; info->screen_base = qfbdev->shadow; info->screen_size = gobj->size; drm_fb_helper_fill_var(info, &qfbdev->helper, sizes->fb_width, sizes->fb_height); /* setup aperture base/size for vesafb takeover */ info->apertures->ranges[0].base = qdev->ddev->mode_config.fb_base; info->apertures->ranges[0].size = qdev->vram_size; info->fix.mmio_start = 0; info->fix.mmio_len = 0; if (info->screen_base == NULL) { ret = -ENOSPC; goto out_destroy_fbi; } info->fbdefio = &qxl_defio; fb_deferred_io_init(info); qdev->fbdev_info = info; qdev->fbdev_qfb = &qfbdev->qfb; DRM_INFO("fb mappable at 0x%lX, size %lu\n", info->fix.smem_start, (unsigned long)info->screen_size); DRM_INFO("fb: depth %d, pitch %d, width %d, height %d\n", fb->depth, fb->pitches[0], fb->width, fb->height); return 0; out_destroy_fbi: drm_fb_helper_release_fbi(&qfbdev->helper); out_unref: if (qbo) { ret = qxl_bo_reserve(qbo, false); if (likely(ret == 0)) { qxl_bo_kunmap(qbo); qxl_bo_unpin(qbo); qxl_bo_unreserve(qbo); } } if (fb && ret) { drm_gem_object_unreference_unlocked(gobj); drm_framebuffer_cleanup(fb); kfree(fb); } drm_gem_object_unreference_unlocked(gobj); return ret; }
static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int bpp = 0; unsigned long ldddsr; int k, m, ret; /* enable clocks before accessing the hardware */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { if (priv->ch[k].enabled) { sh_mobile_lcdc_clk_on(priv); if (!bpp) bpp = priv->ch[k].info->var.bits_per_pixel; } } /* reset */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); /* enable LCDC channels */ tmp = lcdc_read(priv, _LDCNT2R); tmp |= priv->ch[0].enabled; tmp |= priv->ch[1].enabled; lcdc_write(priv, _LDCNT2R, tmp); /* read data from external memory, avoid using the BEU for now */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); /* stop the lcdc first */ sh_mobile_lcdc_start_stop(priv, 0); /* configure clocks */ tmp = priv->lddckr; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; m = ch->cfg.clock_divider; if (!m) continue; if (m == 1) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ lcdc_write_chan(ch, LDDCKPAT1R, 0); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } lcdc_write(priv, _LDDCKR, tmp); /* start dotclock again */ lcdc_write(priv, _LDDCKSTPR, 0); lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); /* interrupts are disabled to begin with */ lcdc_write(priv, _LDINTR, 0); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; sh_mobile_lcdc_geometry(ch); /* power supply */ lcdc_write_chan(ch, LDPMR, 0); board_cfg = &ch->cfg.board_cfg; if (board_cfg->setup_sys) { ret = board_cfg->setup_sys(board_cfg->board_data, ch, &sh_mobile_lcdc_sys_bus_ops); if (ret) return ret; } } /* word and long word swap */ ldddsr = lcdc_read(priv, _LDDDSR); if (priv->ch[0].info->var.nonstd) lcdc_write(priv, _LDDDSR, ldddsr | 7); else { switch (bpp) { case 16: lcdc_write(priv, _LDDDSR, ldddsr | 6); break; case 24: lcdc_write(priv, _LDDDSR, ldddsr | 7); break; case 32: lcdc_write(priv, _LDDDSR, ldddsr | 4); break; } } for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { unsigned long base_addr_y; unsigned long base_addr_c = 0; int pitch; ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; /* set bpp format in PKF[4:0] */ tmp = lcdc_read_chan(ch, LDDFR); tmp &= ~0x0003031f; if (ch->info->var.nonstd) { tmp |= (ch->info->var.nonstd << 16); switch (ch->info->var.bits_per_pixel) { case 12: break; case 16: tmp |= (0x1 << 8); break; case 24: tmp |= (0x2 << 8); break; } } else { switch (ch->info->var.bits_per_pixel) { case 16: tmp |= 0x03; break; case 24: tmp |= 0x0b; break; case 32: break; } } lcdc_write_chan(ch, LDDFR, tmp); base_addr_y = ch->info->fix.smem_start; base_addr_c = base_addr_y + ch->info->var.xres * ch->info->var.yres_virtual; pitch = ch->info->fix.line_length; /* test if we can enable meram */ if (ch->cfg.meram_cfg && priv->meram_dev && priv->meram_dev->ops) { struct sh_mobile_meram_cfg *cfg; struct sh_mobile_meram_info *mdev; unsigned long icb_addr_y, icb_addr_c; int icb_pitch; int pf; cfg = ch->cfg.meram_cfg; mdev = priv->meram_dev; /* we need to de-init configured ICBs before we * we can re-initialize them. */ if (ch->meram_enabled) mdev->ops->meram_unregister(mdev, cfg); ch->meram_enabled = 0; if (ch->info->var.nonstd) { if (ch->info->var.bits_per_pixel == 24) pf = SH_MOBILE_MERAM_PF_NV24; else pf = SH_MOBILE_MERAM_PF_NV; } else { pf = SH_MOBILE_MERAM_PF_RGB; } ret = mdev->ops->meram_register(mdev, cfg, pitch, ch->info->var.yres, pf, base_addr_y, base_addr_c, &icb_addr_y, &icb_addr_c, &icb_pitch); if (!ret) { /* set LDSA1R value */ base_addr_y = icb_addr_y; pitch = icb_pitch; /* set LDSA2R value if required */ if (base_addr_c) base_addr_c = icb_addr_c; ch->meram_enabled = 1; } } /* point out our frame buffer */ lcdc_write_chan(ch, LDSA1R, base_addr_y); if (ch->info->var.nonstd) lcdc_write_chan(ch, LDSA2R, base_addr_c); /* set line size */ lcdc_write_chan(ch, LDMLSR, pitch); /* setup deferred io if SYS bus */ tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; if (ch->ldmt1r_value & (1 << 12) && tmp) { ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; ch->defio.delay = msecs_to_jiffies(tmp); ch->info->fbdefio = &ch->defio; fb_deferred_io_init(ch->info); /* one-shot mode */ lcdc_write_chan(ch, LDSM1R, 1); /* enable "Frame End Interrupt Enable" bit */ lcdc_write(priv, _LDINTR, LDINTR_FE); } else { /* continuous read mode */ lcdc_write_chan(ch, LDSM1R, 0); } } /* display output */ lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); /* start the lcdc */ sh_mobile_lcdc_start_stop(priv, 1); priv->started = 1; /* tell the board code to enable the panel */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; board_cfg = &ch->cfg.board_cfg; if (board_cfg->display_on && try_module_get(board_cfg->owner)) { board_cfg->display_on(board_cfg->board_data, ch->info); module_put(board_cfg->owner); } if (ch->bl) { ch->bl->props.power = FB_BLANK_UNBLANK; backlight_update_status(ch->bl); } } return 0; }
static int ws_eink_spi_probe(struct spi_device *spi) { struct fb_info *info; int retval = 0; struct waveshare_eink_platform_data *pdata; const struct spi_device_id *spi_id; const struct waveshare_eink_device_properties *dev_props; struct ws_eink_fb_par *par; int vmem_size; pdata = spi->dev.platform_data; if (!pdata) { dev_err(&spi->dev, "Required platform data was not provided"); return -EINVAL; } spi_id = spi_get_device_id(spi); if (!spi_id) { dev_err(&spi->dev, "device id not supported!\n"); return -EINVAL; } dev_props = (const struct waveshare_eink_device_properties *) spi_id->driver_data; if (!dev_props) { dev_err(&spi->dev, "device definition lacks driver_data\n"); return -EINVAL; } info = framebuffer_alloc(sizeof(struct ws_eink_fb_par), &spi->dev); if (!info) return -ENOMEM; vmem_size = dev_props->width * dev_props->height * dev_props->bpp / 8; info->screen_base = vzalloc(vmem_size); if (!info->screen_base) { retval = -ENOMEM; goto screen_base_fail; } info->fbops = &ws_eink_ops; WARN_ON(strlcpy(info->fix.id, "waveshare_eink", sizeof(info->fix.id)) >= sizeof(info->fix.id)); info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; info->fix.smem_len = vmem_size; info->fix.xpanstep = 0; info->fix.ypanstep = 0; info->fix.ywrapstep = 0; info->fix.line_length = dev_props->width * dev_props->bpp / 8; info->var.xres = dev_props->width; info->var.yres = dev_props->height; info->var.xres_virtual = dev_props->width; info->var.yres_virtual = dev_props->height; info->var.bits_per_pixel = dev_props->bpp; info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; info->fbdefio = &ws_eink_defio; fb_deferred_io_init(info); par = info->par; par->info = info; par->spi = spi; par->props = dev_props; par->rst = pdata->rst_gpio; par->dc = pdata->dc_gpio; par->busy = pdata->busy_gpio; par->ssbuf = vzalloc(vmem_size); if (!par->ssbuf) { retval = -ENOMEM; goto ssbuf_alloc_fail; } retval = register_framebuffer(info); if (retval < 0) { dev_err(&spi->dev, "framebuffer registration failed"); goto fbreg_fail; } spi_set_drvdata(spi, info); retval = ws_eink_init_display(par); if (retval) { dev_err(&spi->dev, "display initialization failed"); goto disp_init_fail; } dev_dbg(&spi->dev, "fb%d: %s frame buffer device,\n\tusing %d KiB of video memory\n", info->node, info->fix.id, vmem_size); return 0; disp_init_fail: framebuffer_release(info); fbreg_fail: vfree(par->ssbuf); ssbuf_alloc_fail: vfree(info->screen_base); screen_base_fail: vfree(info->screen_base); return retval; }
static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int bpp = 0; int k, m; int ret = 0; /* enable clocks before accessing the hardware */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { if (priv->ch[k].enabled) { sh_mobile_lcdc_clk_on(priv); if (!bpp) bpp = priv->ch[k].info->var.bits_per_pixel; } } /* reset */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); /* enable LCDC channels */ tmp = lcdc_read(priv, _LDCNT2R); tmp |= priv->ch[0].enabled; tmp |= priv->ch[1].enabled; lcdc_write(priv, _LDCNT2R, tmp); /* read data from external memory, avoid using the BEU for now */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); /* stop the lcdc first */ sh_mobile_lcdc_start_stop(priv, 0); /* configure clocks */ tmp = priv->lddckr; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; m = ch->cfg.clock_divider; if (!m) continue; if (m == 1) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ lcdc_write_chan(ch, LDDCKPAT1R, 0); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } lcdc_write(priv, _LDDCKR, tmp); /* start dotclock again */ lcdc_write(priv, _LDDCKSTPR, 0); lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); /* interrupts are disabled to begin with */ lcdc_write(priv, _LDINTR, 0); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; sh_mobile_lcdc_geometry(ch); /* power supply */ lcdc_write_chan(ch, LDPMR, 0); board_cfg = &ch->cfg.board_cfg; if (board_cfg->setup_sys) ret = board_cfg->setup_sys(board_cfg->board_data, ch, &sh_mobile_lcdc_sys_bus_ops); if (ret) return ret; } /* word and long word swap */ switch (bpp) { case 16: lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); break; case 24: lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 7); break; case 32: lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 4); break; } for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; /* set bpp format in PKF[4:0] */ tmp = lcdc_read_chan(ch, LDDFR); tmp &= ~0x0001001f; switch (ch->info->var.bits_per_pixel) { case 16: tmp |= 0x03; break; case 24: tmp |= 0x0b; break; case 32: break; } lcdc_write_chan(ch, LDDFR, tmp); /* point out our frame buffer */ lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); /* set line size */ lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); /* setup deferred io if SYS bus */ tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; if (ch->ldmt1r_value & (1 << 12) && tmp) { ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; ch->defio.delay = msecs_to_jiffies(tmp); ch->info->fbdefio = &ch->defio; fb_deferred_io_init(ch->info); /* one-shot mode */ lcdc_write_chan(ch, LDSM1R, 1); /* enable "Frame End Interrupt Enable" bit */ lcdc_write(priv, _LDINTR, LDINTR_FE); } else { /* continuous read mode */ lcdc_write_chan(ch, LDSM1R, 0); } } /* display output */ lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); /* start the lcdc */ sh_mobile_lcdc_start_stop(priv, 1); priv->started = 1; /* tell the board code to enable the panel */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; board_cfg = &ch->cfg.board_cfg; if (try_module_get(board_cfg->owner) && board_cfg->display_on) { board_cfg->display_on(board_cfg->board_data, ch->info); module_put(board_cfg->owner); } } return 0; }
static int __devinit st7735fb_probe (struct spi_device *spi) { int chip = spi_get_device_id(spi)->driver_data; struct st7735fb_platform_data *pdata = spi->dev.platform_data; int vmem_size = WIDTH*HEIGHT*BPP/8; u8 *vmem; struct fb_info *info; struct st7735fb_par *par; int retval = -ENOMEM; if (chip != ST7735_DISPLAY_AF_TFT18) { pr_err("%s: only the %s device is supported\n", DRVNAME, to_spi_driver(spi->dev.driver)->id_table->name); return -EINVAL; } if (!pdata) { pr_err("%s: platform data required for rst and dc info\n", DRVNAME); return -EINVAL; } vmem = vzalloc(vmem_size); if (!vmem) return retval; info = framebuffer_alloc(sizeof(struct st7735fb_par), &spi->dev); if (!info) goto fballoc_fail; info->screen_base = (u8 __force __iomem *)vmem; info->fbops = &st7735fb_ops; info->fix = st7735fb_fix; info->fix.smem_len = vmem_size; info->var = st7735fb_var; /* Choose any packed pixel format as long as it's RGB565 */ info->var.red.offset = 11; info->var.red.length = 5; info->var.green.offset = 5; info->var.green.length = 6; info->var.blue.offset = 0; info->var.blue.length = 5; info->var.transp.offset = 0; info->var.transp.length = 0; info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; info->fbdefio = &st7735fb_defio; fb_deferred_io_init(info); par = info->par; par->info = info; par->spi = spi; par->rst = pdata->rst_gpio; par->dc = pdata->dc_gpio; #ifdef __LITTLE_ENDIAN /* Allocate swapped shadow buffer */ vmem = vzalloc(vmem_size); if (!vmem) return retval; par->ssbuf = vmem; #endif retval = register_framebuffer(info); if (retval < 0) goto fbreg_fail; spi_set_drvdata(spi, info); retval = st7735fb_init_display(par); if (retval < 0) goto init_fail; printk(KERN_INFO "fb%d: %s frame buffer device,\n\tusing %d KiB of video memory\n", info->node, info->fix.id, vmem_size); return 0; /* TODO: release gpios on fail */ init_fail: spi_set_drvdata(spi, NULL); fbreg_fail: framebuffer_release(info); fballoc_fail: vfree(vmem); return retval; }
static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; struct fb_videomode *lcd_cfg; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int k, m; int ret = 0; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) if (priv->ch[k].enabled) sh_mobile_lcdc_clk_on(priv); lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); tmp = lcdc_read(priv, _LDCNT2R); tmp |= priv->ch[0].enabled; tmp |= priv->ch[1].enabled; lcdc_write(priv, _LDCNT2R, tmp); lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); sh_mobile_lcdc_start_stop(priv, 0); tmp = priv->lddckr; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; m = ch->cfg.clock_divider; if (!m) continue; if (m == 1) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } lcdc_write(priv, _LDDCKR, tmp); lcdc_write(priv, _LDDCKSTPR, 0); lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); lcdc_write(priv, _LDINTR, 0); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; lcd_cfg = &ch->cfg.lcd_cfg; if (!ch->enabled) continue; tmp = ch->ldmt1r_value; tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; lcdc_write_chan(ch, LDMT1R, tmp); lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); tmp = lcd_cfg->xres + lcd_cfg->hsync_len; tmp += lcd_cfg->left_margin; tmp += lcd_cfg->right_margin; tmp /= 8; tmp |= (lcd_cfg->xres / 8) << 16; lcdc_write_chan(ch, LDHCNR, tmp); tmp = lcd_cfg->xres; tmp += lcd_cfg->right_margin; tmp /= 8; tmp |= (lcd_cfg->hsync_len / 8) << 16; lcdc_write_chan(ch, LDHSYNR, tmp); lcdc_write_chan(ch, LDPMR, 0); tmp = lcd_cfg->yres + lcd_cfg->vsync_len; tmp += lcd_cfg->upper_margin; tmp += lcd_cfg->lower_margin; tmp |= lcd_cfg->yres << 16; lcdc_write_chan(ch, LDVLNR, tmp); tmp = lcd_cfg->yres; tmp += lcd_cfg->lower_margin; tmp |= lcd_cfg->vsync_len << 16; lcdc_write_chan(ch, LDVSYNR, tmp); board_cfg = &ch->cfg.board_cfg; if (board_cfg->setup_sys) ret = board_cfg->setup_sys(board_cfg->board_data, ch, &sh_mobile_lcdc_sys_bus_ops); if (ret) return ret; } lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; tmp = lcdc_read_chan(ch, LDDFR); tmp &= ~(0x0001001f); tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; lcdc_write_chan(ch, LDDFR, tmp); lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; if (ch->ldmt1r_value & (1 << 12) && tmp) { ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; ch->defio.delay = msecs_to_jiffies(tmp); ch->info->fbdefio = &ch->defio; fb_deferred_io_init(ch->info); lcdc_write_chan(ch, LDSM1R, 1); lcdc_write(priv, _LDINTR, LDINTR_FE); } else { lcdc_write_chan(ch, LDSM1R, 0); } } lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); sh_mobile_lcdc_start_stop(priv, 1); priv->started = 1; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; board_cfg = &ch->cfg.board_cfg; if (board_cfg->display_on) board_cfg->display_on(board_cfg->board_data); } return 0; }
static int __devinit st7585_probe(struct spi_device *spi) { struct st7585_data *drvdata; int ret; drvdata = devm_kzalloc(&spi->dev, sizeof(*drvdata), GFP_KERNEL); if (!drvdata) return -ENOMEM; drvdata->spi = spi; spin_lock_init(&drvdata->lock); spi_set_drvdata(spi, drvdata); spi->mode = 3; spi->bits_per_word = 9; spi->max_speed_hz = 10000000; ret = spi_setup(spi); if (ret) return ret; spisend(drvdata, 0x21); spisend(drvdata, 0x90); spisend(drvdata, 0x20); spisend(drvdata, 0x0c); spisend(drvdata, 0x8e); drvdata->info = framebuffer_alloc(0, &spi->dev); if (!drvdata->info) { return -ENOMEM; } st7585_fix.smem_start = (unsigned long)drvdata->vram; st7585_fix.smem_len = VRAM_LEN; drvdata->info->par = drvdata; drvdata->info->flags = FBINFO_DEFAULT; drvdata->info->var = st7585_var; drvdata->info->fix = st7585_fix; drvdata->info->monspecs.hfmin = 0; drvdata->info->monspecs.hfmax = 0; drvdata->info->monspecs.vfmin = 10000; drvdata->info->monspecs.vfmax = 10000; drvdata->info->monspecs.dpms = 0; drvdata->info->fbops = &st7585fb_ops; drvdata->info->screen_base = drvdata->vram; drvdata->info->fbdefio = &st7585fb_defio; fb_deferred_io_init(drvdata->info); ret = register_framebuffer(drvdata->info); if (ret < 0) { framebuffer_release(drvdata->info); return -EINVAL; } printk(KERN_INFO "fb%d: %s frame buffer device\n", drvdata->info->node, drvdata->info->fix.id); return 0; }
static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; struct fb_videomode *lcd_cfg; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int k, m; int ret = 0; /* enable clocks before accessing the hardware */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) if (priv->ch[k].enabled) sh_mobile_lcdc_clk_on(priv); /* reset */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET); lcdc_wait_bit(priv, _LDCNT2R, LCDC_RESET, 0); /* enable LCDC channels */ tmp = lcdc_read(priv, _LDCNT2R); tmp |= priv->ch[0].enabled; tmp |= priv->ch[1].enabled; lcdc_write(priv, _LDCNT2R, tmp); /* read data from external memory, avoid using the BEU for now */ lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) & ~DISPLAY_BEU); /* stop the lcdc first */ sh_mobile_lcdc_start_stop(priv, 0); /* configure clocks */ tmp = priv->lddckr; for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; m = ch->cfg.clock_divider; if (!m) continue; if (m == 1) m = 1 << 6; tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); } lcdc_write(priv, _LDDCKR, tmp); /* start dotclock again */ lcdc_write(priv, _LDDCKSTPR, 0); lcdc_wait_bit(priv, _LDDCKSTPR, ~0, 0); /* interrupts are disabled to begin with */ lcdc_write(priv, _LDINTR, 0); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; lcd_cfg = &ch->cfg.lcd_cfg; if (!ch->enabled) continue; tmp = ch->ldmt1r_value; tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; lcdc_write_chan(ch, LDMT1R, tmp); /* setup SYS bus */ lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); /* horizontal configuration */ tmp = lcd_cfg->xres + lcd_cfg->hsync_len; tmp += lcd_cfg->left_margin; tmp += lcd_cfg->right_margin; tmp /= 8; /* HTCN */ tmp |= (lcd_cfg->xres / 8) << 16; /* HDCN */ lcdc_write_chan(ch, LDHCNR, tmp); tmp = lcd_cfg->xres; tmp += lcd_cfg->right_margin; tmp /= 8; /* HSYNP */ tmp |= (lcd_cfg->hsync_len / 8) << 16; /* HSYNW */ lcdc_write_chan(ch, LDHSYNR, tmp); /* power supply */ lcdc_write_chan(ch, LDPMR, 0); /* vertical configuration */ tmp = lcd_cfg->yres + lcd_cfg->vsync_len; tmp += lcd_cfg->upper_margin; tmp += lcd_cfg->lower_margin; /* VTLN */ tmp |= lcd_cfg->yres << 16; /* VDLN */ lcdc_write_chan(ch, LDVLNR, tmp); tmp = lcd_cfg->yres; tmp += lcd_cfg->lower_margin; /* VSYNP */ tmp |= lcd_cfg->vsync_len << 16; /* VSYNW */ lcdc_write_chan(ch, LDVSYNR, tmp); board_cfg = &ch->cfg.board_cfg; if (board_cfg->setup_sys) ret = board_cfg->setup_sys(board_cfg->board_data, ch, &sh_mobile_lcdc_sys_bus_ops); if (ret) return ret; } /* word and long word swap */ lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6); for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!priv->ch[k].enabled) continue; /* set bpp format in PKF[4:0] */ tmp = lcdc_read_chan(ch, LDDFR); tmp &= ~(0x0001001f); tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; lcdc_write_chan(ch, LDDFR, tmp); /* point out our frame buffer */ lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start); /* set line size */ lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length); /* setup deferred io if SYS bus */ tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; if (ch->ldmt1r_value & (1 << 12) && tmp) { ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; ch->defio.delay = msecs_to_jiffies(tmp); ch->info->fbdefio = &ch->defio; fb_deferred_io_init(ch->info); /* one-shot mode */ lcdc_write_chan(ch, LDSM1R, 1); /* enable "Frame End Interrupt Enable" bit */ lcdc_write(priv, _LDINTR, LDINTR_FE); } else { /* continuous read mode */ lcdc_write_chan(ch, LDSM1R, 0); } } /* display output */ lcdc_write(priv, _LDCNT1R, LCDC_ENABLE); /* start the lcdc */ sh_mobile_lcdc_start_stop(priv, 1); priv->started = 1; /* tell the board code to enable the panel */ for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; if (!ch->enabled) continue; board_cfg = &ch->cfg.board_cfg; if (board_cfg->display_on) board_cfg->display_on(board_cfg->board_data); } return 0; }
static int memlcd_spi_probe(struct spi_device *spi) { memlcd_priv *priv = NULL; int ret = -EINVAL; /* allocate private data */ priv = (memlcd_priv*)kzalloc(sizeof(memlcd_priv),GFP_KERNEL); if(priv == NULL) { dev_err(&spi->dev, "Allocate private data failed!"); return -ENOMEM; } dev_set_drvdata(&spi->dev,priv); priv->spi = spi; /* configure spi */ spi->bits_per_word = 8; spi->max_speed_hz = 2000000; ret = spi_setup(spi); if (ret < 0) { dev_err(&spi->dev, "Configure spi host phase failed!"); goto free_priv; } /* allocate framebuffer */ priv->info = framebuffer_alloc(0, &spi->dev); if(priv->info == NULL) { dev_err(&spi->dev, "Allocate framebuffer failed!"); ret = -ENOMEM; goto free_priv; } /* allocate spi data transfer buffer */ priv->spi_buf = kzalloc( LS027B7DH01_HEIGHT * sizeof(memlcd_line_update) + 2, GFP_KERNEL); if(priv->spi_buf == NULL) { dev_err(&spi->dev,"Allocate data for spi transfers failed!"); ret = -ENOMEM; goto free_fb; } /* allocate video memory */ priv->video_memory = kzalloc(LS027B7DH01_SCREEN_SIZE, GFP_KERNEL); if(priv->video_memory == NULL) { dev_err(&spi->dev, "Allocate video memory failed!"); ret = -ENOMEM; goto free_spi_data; } /* configure framebuffer device */ priv->info->par = priv; priv->info->screen_base = (char __iomem *)priv->video_memory; priv->info->screen_size = LS027B7DH01_SCREEN_SIZE; priv->info->fbops = &ls027b7dh01_ops; priv->info->fix = ls027b7dh01_fix; priv->info->fix.smem_start = (unsigned long)priv->video_memory; priv->info->fix.smem_len = LS027B7DH01_SCREEN_SIZE; priv->info->var = ls027b7dh01_var; priv->info->fbdefio = &ls027b7dh01_defio; priv->info->pseudo_palette = NULL; priv->info->flags = FBINFO_FLAG_DEFAULT; /* init deferred io structure */ fb_deferred_io_init(priv->info); /* register framebuffer */ ret = register_framebuffer(priv->info); if(ret < 0) { dev_err(&spi->dev,"Register framebuffer failed!"); goto free_fb; } dev_info(&spi->dev,"Framebuffer device registered successfully!"); return 0; free_spi_data: kfree(priv->spi_buf); free_fb: kfree(priv->info); free_priv: kfree(priv); return ret; }
int ili9341_probe_spi(struct spi_device *spi) { struct device *dev = &spi->dev; struct ili9341 *ili; struct fb_info *info; int ret = 0; /* verify we where given some information */ ili = devm_kzalloc(&spi->dev, sizeof(struct ili9341), GFP_KERNEL); if (ili == NULL) { dev_err(dev, "no memory for device\n"); return -ENOMEM; } ili->dev = dev; spi->mode = SPI_MODE_0; spi_setup(spi); spi_set_drvdata(spi, ili); dev_info(&spi->dev, "spi registered, item=0x%p\n", (void *)ili); ili->gpiodc = 16; gpio_request(ili->gpiodc, "ili9341 dc pin"); gpio_direction_output(ili->gpiodc, 0); dev_info(&spi->dev, "gpio %i registered\n", ili->gpiodc); ili->gpiorst = 12; gpio_request(ili->gpiorst, "ili9341 reset pin"); gpio_direction_output(ili->gpiorst, 0); dev_info(&spi->dev, "gpio %i registered\n", ili->gpiorst); ili->spi = spi; info = framebuffer_alloc(sizeof(struct ili9341), &spi->dev); if (!info) { ret = -ENOMEM; dev_err(&spi->dev, "%s: unable to framebuffer_alloc\n", __func__); goto out_item; } info->pseudo_palette = &ili->pseudo_palette; ili->info = info; info->par = ili; info->dev = &spi->dev; info->fbops = &ili9341_fbops; info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; info->fix = ili9341_fix; info->var = ili9341_var; ret = ili9341_video_alloc(ili); if (ret) { dev_err(&spi->dev, "%s: unable to ili9341_video_alloc\n", __func__); goto out_info; } info->screen_base = (char __iomem *)ili->info->fix.smem_start; ret = ili9341_pages_alloc(ili); if (ret < 0) { dev_err(&spi->dev, "%s: unable to ili9341_pages_init\n", __func__); goto out_video; } info->fbdefio = &ili9341_defio; fb_deferred_io_init(info); ret = register_framebuffer(info); if (ret < 0) { dev_err(&spi->dev, "%s: unable to register_frambuffer\n", __func__); goto out_pages; } ili9341_init_chip(ili); ili9341_update_all(ili); return ret; out_pages: ili9341_pages_free(ili); out_video: ili9341_video_free(ili); out_info: framebuffer_release(info); out_item: kfree(ili); return ret; }
static int __devinit st7586fb_probe (struct spi_device *spi) { int chip = spi_get_device_id(spi)->driver_data; struct st7586fb_platform_data *pdata = spi->dev.platform_data; int vmem_size = (WIDTH + 2) / 3 * HEIGHT; u8 *vmem; struct fb_info *info; struct st7586fb_par *par; int retval = -ENOMEM; if (chip != ST7586_DISPLAY_LEGO_EV3) { pr_err("%s: only the %s device is supported\n", DRVNAME, to_spi_driver(spi->dev.driver)->id_table->name); return -EINVAL; } if (!pdata) { pr_err("%s: platform data required for rst and a0 info\n", DRVNAME); return -EINVAL; } vmem = (u8 *)kmalloc(vmem_size, GFP_KERNEL); if (!vmem) return retval; // Zero memory for easy detection if any new data has been written to screenbuffer memset(vmem, 0, vmem_size); info = framebuffer_alloc(sizeof(struct st7586fb_par), &spi->dev); if (!info) goto fballoc_fail; info->screen_base = vmem; info->fbops = &st7586fb_ops; info->fix = st7586fb_fix; info->fix.smem_start = virt_to_phys(vmem); info->fix.smem_len = vmem_size; info->var = st7586fb_var; info->var.red.offset = 0; info->var.red.length = 1; info->var.green.offset = 0; info->var.green.length = 1; info->var.blue.offset = 0; info->var.blue.length = 1; info->var.transp.offset = 0; info->var.transp.length = 0; info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; info->fbdefio = &st7586fb_defio; fb_deferred_io_init(info); par = info->par; par->info = info; par->spi = spi; par->rst = pdata->rst_gpio; par->a0 = pdata->a0_gpio; par->cs = pdata->cs_gpio; par->buf = kmalloc(1, GFP_KERNEL); INIT_DELAYED_WORK(&par->dwork, st7586fb_deferred_work); retval = register_framebuffer(info); if (retval < 0) goto fbreg_fail; spi_set_drvdata(spi, info); retval = st7586fb_request_gpios(par); // Move initing of display to ioctl call to avoid dispaly flickering // as dispaly has already been inited in uboot // retval |= st7586fb_init_display(par); if (retval < 0) goto init_fail; printk(KERN_INFO "fb%d: %s frame buffer device, using %d.%d KiB of video memory\n", info->node, info->fix.id, vmem_size / 1024, vmem_size % 1024 * 10 / 1024); return 0; init_fail: spi_set_drvdata(spi, NULL); fbreg_fail: kfree(par->buf); framebuffer_release(info); fballoc_fail: kfree(vmem); return retval; }