9
0
Fork 0

Merge branch 'for-next/video'

This commit is contained in:
Sascha Hauer 2017-03-13 08:16:53 +01:00
commit 97d2da3d98
15 changed files with 3404 additions and 38 deletions

View File

@ -169,6 +169,7 @@ static int do_fbtest(int argc, char *argv[])
pattern = patterns[i++ % ARRAY_SIZE(patterns)].func; pattern = patterns[i++ % ARRAY_SIZE(patterns)].func;
pattern(sc, color); pattern(sc, color);
gu_screen_blit(sc); gu_screen_blit(sc);
fb_flush(sc->info);
start = get_time_ns(); start = get_time_ns();
while (!is_timeout(start, 2 * SECOND)) while (!is_timeout(start, 2 * SECOND))

View File

@ -59,6 +59,39 @@ static struct kfifo __console_output_fifo;
static struct kfifo *console_input_fifo = &__console_input_fifo; static struct kfifo *console_input_fifo = &__console_input_fifo;
static struct kfifo *console_output_fifo = &__console_output_fifo; static struct kfifo *console_output_fifo = &__console_output_fifo;
int console_open(struct console_device *cdev)
{
int ret;
if (cdev->open && !cdev->open_count) {
ret = cdev->open(cdev);
if (ret)
return ret;
}
cdev->open_count++;
return 0;
}
int console_close(struct console_device *cdev)
{
int ret;
if (!cdev->open_count)
return -EBADFD;
cdev->open_count--;
if (cdev->close && !cdev->open_count) {
ret = cdev->close(cdev);
if (ret)
return ret;
}
return 0;
}
int console_set_active(struct console_device *cdev, unsigned flag) int console_set_active(struct console_device *cdev, unsigned flag)
{ {
int ret, i; int ret, i;
@ -71,8 +104,15 @@ int console_set_active(struct console_device *cdev, unsigned flag)
if (!flag && cdev->f_active && cdev->flush) if (!flag && cdev->f_active && cdev->flush)
cdev->flush(cdev); cdev->flush(cdev);
if (cdev->set_active) { if (flag == cdev->f_active)
ret = cdev->set_active(cdev, flag); return 0;
if (!flag) {
ret = console_close(cdev);
if (ret)
return ret;
} else {
ret = console_open(cdev);
if (ret) if (ret)
return ret; return ret;
} }
@ -232,6 +272,40 @@ static int __console_puts(struct console_device *cdev, const char *s)
return n; return n;
} }
static int fops_open(struct cdev *cdev, unsigned long flags)
{
struct console_device *priv = cdev->priv;
return console_open(priv);
}
static int fops_close(struct cdev *dev)
{
struct console_device *priv = dev->priv;
return console_close(priv);
}
static int fops_flush(struct cdev *dev)
{
struct console_device *priv = dev->priv;
if (priv->flush)
priv->flush(priv);
return 0;
}
static int fops_write(struct cdev* dev, const void* buf, size_t count,
loff_t offset, ulong flags)
{
struct console_device *priv = dev->priv;
priv->puts(priv, buf);
return 0;
}
int console_register(struct console_device *newcdev) int console_register(struct console_device *newcdev)
{ {
struct device_d *dev = &newcdev->class_dev; struct device_d *dev = &newcdev->class_dev;
@ -264,6 +338,8 @@ int console_register(struct console_device *newcdev)
if (newcdev->putc && !newcdev->puts) if (newcdev->putc && !newcdev->puts)
newcdev->puts = __console_puts; newcdev->puts = __console_puts;
newcdev->open_count = 0;
dev_add_param(dev, "active", console_active_set, console_active_get, 0); dev_add_param(dev, "active", console_active_set, console_active_get, 0);
if (IS_ENABLED(CONFIG_CONSOLE_ACTIVATE_FIRST)) { if (IS_ENABLED(CONFIG_CONSOLE_ACTIVATE_FIRST)) {
@ -284,6 +360,25 @@ int console_register(struct console_device *newcdev)
console_set_active(newcdev, CONSOLE_STDIN | console_set_active(newcdev, CONSOLE_STDIN |
CONSOLE_STDOUT | CONSOLE_STDERR); CONSOLE_STDOUT | CONSOLE_STDERR);
/* expose console as device in fs */
newcdev->devfs.name = basprintf("%s%d", newcdev->class_dev.name,
newcdev->class_dev.id);
newcdev->devfs.priv = newcdev;
newcdev->devfs.dev = dev;
newcdev->devfs.ops = &newcdev->fops;
newcdev->devfs.flags = DEVFS_IS_CHARACTER_DEV;
newcdev->fops.open = fops_open;
newcdev->fops.close = fops_close;
newcdev->fops.flush = fops_flush;
newcdev->fops.write = fops_write;
ret = devfs_create(&newcdev->devfs);
if (ret) {
pr_err("device creation failed with %s\n", strerror(-ret));
return ret;
}
return 0; return 0;
} }
EXPORT_SYMBOL(console_register); EXPORT_SYMBOL(console_register);

View File

@ -12,6 +12,10 @@ config FRAMEBUFFER_CONSOLE
select FONTS select FONTS
prompt "framebuffer console support" prompt "framebuffer console support"
config DRIVER_VIDEO_FB_SSD1307
bool "Solomon SSD1307 framebuffer support"
depends on I2C && GPIOLIB
config VIDEO_VPL config VIDEO_VPL
depends on OFTREE depends on OFTREE
bool bool

View File

@ -21,5 +21,5 @@ obj-$(CONFIG_DRIVER_VIDEO_OMAP) += omap.o
obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o obj-$(CONFIG_DRIVER_VIDEO_BCM283X) += bcm2835.o
obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o obj-$(CONFIG_DRIVER_VIDEO_SIMPLEFB) += simplefb.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/ obj-$(CONFIG_DRIVER_VIDEO_IMX_IPUV3) += imx-ipu-v3/
obj-$(CONFIG_DRIVER_VIDEO_EFI_GOP) += efi_gop.o obj-$(CONFIG_DRIVER_VIDEO_EFI_GOP) += efi_gop.o
obj-$(CONFIG_DRIVER_VIDEO_FB_SSD1307) += ssd1307fb.o

View File

@ -12,25 +12,51 @@ static int fb_ioctl(struct cdev* cdev, int req, void *data)
{ {
struct fb_info *info = cdev->priv; struct fb_info *info = cdev->priv;
struct fb_info **fb; struct fb_info **fb;
int ret;
switch (req) { switch (req) {
case FBIOGET_SCREENINFO: case FBIOGET_SCREENINFO:
fb = data; fb = data;
*fb = info; *fb = info;
ret = 0;
break; break;
case FBIO_ENABLE: case FBIO_ENABLE:
info->fbops->fb_enable(info); ret = fb_enable(info);
break; break;
case FBIO_DISABLE: case FBIO_DISABLE:
info->fbops->fb_disable(info); ret = fb_disable(info);
break; break;
default: default:
return -ENOSYS; return -ENOSYS;
} }
return ret;
}
static int fb_close(struct cdev *cdev)
{
struct fb_info *info = cdev->priv;
if (info->fbops->fb_flush)
info->fbops->fb_flush(info);
return 0; return 0;
} }
static int fb_op_flush(struct cdev *cdev)
{
struct fb_info *info = cdev->priv;
if (info->fbops->fb_flush)
info->fbops->fb_flush(info);
return 0;
}
void fb_flush(struct fb_info *info)
{
if (info->fbops->fb_flush)
info->fbops->fb_flush(info);
}
static void fb_release_shadowfb(struct fb_info *info) static void fb_release_shadowfb(struct fb_info *info)
{ {
free(info->screen_base_shadow); free(info->screen_base_shadow);
@ -70,7 +96,8 @@ int fb_enable(struct fb_info *info)
if (ret) if (ret)
return ret; return ret;
info->fbops->fb_enable(info); if (info->fbops->fb_enable)
info->fbops->fb_enable(info);
info->enabled = true; info->enabled = true;
@ -82,7 +109,8 @@ int fb_disable(struct fb_info *info)
if (!info->enabled) if (!info->enabled)
return 0; return 0;
info->fbops->fb_disable(info); if (info->fbops->fb_disable)
info->fbops->fb_disable(info);
fb_release_shadowfb(info); fb_release_shadowfb(info);
@ -199,6 +227,8 @@ static struct file_operations fb_ops = {
.memmap = generic_memmap_rw, .memmap = generic_memmap_rw,
.lseek = dev_lseek_default, .lseek = dev_lseek_default,
.ioctl = fb_ioctl, .ioctl = fb_ioctl,
.close = fb_close,
.flush = fb_op_flush,
}; };
static void fb_print_mode(struct fb_videomode *mode) static void fb_print_mode(struct fb_videomode *mode)

View File

@ -11,6 +11,7 @@ enum state_t {
LIT, /* Literal input */ LIT, /* Literal input */
ESC, /* Start of escape sequence */ ESC, /* Start of escape sequence */
CSI, /* Reading arguments in "CSI Pn ;...*/ CSI, /* Reading arguments in "CSI Pn ;...*/
CSI_CNT,
}; };
struct fbc_priv { struct fbc_priv {
@ -34,10 +35,12 @@ struct fbc_priv {
#define ANSI_FLAG_INVERT (1 << 0) #define ANSI_FLAG_INVERT (1 << 0)
#define ANSI_FLAG_BRIGHT (1 << 1) #define ANSI_FLAG_BRIGHT (1 << 1)
#define HIDE_CURSOR (1 << 2)
unsigned flags; unsigned flags;
int csipos; int csipos;
u8 csi[256]; u8 csi[256];
unsigned char csi_cmd;
int active; int active;
int in_console; int in_console;
@ -144,6 +147,12 @@ static void video_invertchar(struct fbc_priv *priv, int x, int y)
priv->font->width, priv->font->height); priv->font->width, priv->font->height);
} }
static void show_cursor(struct fbc_priv *priv, int x, int y)
{
if (!(priv->flags & HIDE_CURSOR))
video_invertchar(priv, x, y);
}
static void printchar(struct fbc_priv *priv, int c) static void printchar(struct fbc_priv *priv, int c)
{ {
video_invertchar(priv, priv->x, priv->y); video_invertchar(priv, priv->x, priv->y);
@ -200,7 +209,7 @@ static void printchar(struct fbc_priv *priv, int c)
priv->y = priv->rows; priv->y = priv->rows;
} }
video_invertchar(priv, priv->x, priv->y); show_cursor(priv, priv->x, priv->y);
return; return;
} }
@ -258,17 +267,51 @@ static void fbc_parse_csi(struct fbc_priv *priv)
case 'm': case 'm':
fbc_parse_colors(priv); fbc_parse_colors(priv);
return; return;
case '?': /* vt100: show/hide cursor */
priv->csi_cmd = last;
priv->state = CSI_CNT;
return;
case 'h':
/* suffix for vt100 "[?25h" */
switch (priv->csi_cmd) {
case '?': /* cursor visible */
priv->csi_cmd = -1;
if (!(priv->flags & HIDE_CURSOR))
break;
priv->flags &= ~HIDE_CURSOR;
/* show cursor now */
show_cursor(priv, priv->x, priv->y);
break;
}
break;
case 'l':
/* suffix for vt100 "[?25l" */
switch (priv->csi_cmd) {
case '?': /* cursor invisible */
priv->csi_cmd = -1;
/* hide cursor now */
video_invertchar(priv, priv->x, priv->y);
priv->flags |= HIDE_CURSOR;
break;
}
break;
case 'J': case 'J':
cls(priv); cls(priv);
video_invertchar(priv, priv->x, priv->y); show_cursor(priv, priv->x, priv->y);
return; return;
case 'H': case 'H':
video_invertchar(priv, priv->x, priv->y); show_cursor(priv, priv->x, priv->y);
pos = simple_strtoul(priv->csi, &end, 10); pos = simple_strtoul(priv->csi, &end, 10);
priv->y = pos ? pos - 1 : 0; priv->y = clamp(pos - 1, 0, (int) priv->rows);
pos = simple_strtoul(end + 1, NULL, 10); pos = simple_strtoul(end + 1, NULL, 10);
priv->x = pos ? pos - 1 : 0; priv->x = clamp(pos - 1, 0, (int) priv->cols);
video_invertchar(priv, priv->x, priv->y);
show_cursor(priv, priv->x, priv->y);
case 'K': case 'K':
pos = simple_strtoul(priv->csi, &end, 10); pos = simple_strtoul(priv->csi, &end, 10);
video_invertchar(priv, priv->x, priv->y); video_invertchar(priv, priv->x, priv->y);
@ -292,6 +335,7 @@ static void fbc_putc(struct console_device *cdev, char c)
{ {
struct fbc_priv *priv = container_of(cdev, struct fbc_priv *priv = container_of(cdev,
struct fbc_priv, cdev); struct fbc_priv, cdev);
struct fb_info *fb = priv->fb;
if (priv->in_console) if (priv->in_console)
return; return;
@ -340,11 +384,18 @@ static void fbc_putc(struct console_device *cdev, char c)
break; break;
default: default:
fbc_parse_csi(priv); fbc_parse_csi(priv);
priv->state = LIT; if (priv->state != CSI_CNT)
priv->state = LIT;
} }
break; break;
case CSI_CNT:
priv->state = CSI;
break;
} }
priv->in_console = 0; priv->in_console = 0;
fb_flush(fb);
} }
static int setup_font(struct fbc_priv *priv) static int setup_font(struct fbc_priv *priv)
@ -365,21 +416,13 @@ static int setup_font(struct fbc_priv *priv)
return 0; return 0;
} }
static int fbc_set_active(struct console_device *cdev, unsigned flags) static int fbc_open(struct console_device *cdev)
{ {
struct fbc_priv *priv = container_of(cdev, struct fbc_priv *priv = container_of(cdev,
struct fbc_priv, cdev); struct fbc_priv, cdev);
struct fb_info *fb = priv->fb; struct fb_info *fb = priv->fb;
int ret; int ret;
if (priv->active) {
fb_close(priv->sc);
priv->active = false;
}
if (!(flags & (CONSOLE_STDOUT | CONSOLE_STDERR)))
return 0;
ret = setup_font(priv); ret = setup_font(priv);
if (ret) if (ret)
return ret; return ret;
@ -400,6 +443,21 @@ static int fbc_set_active(struct console_device *cdev, unsigned flags)
return 0; return 0;
} }
static int fbc_close(struct console_device *cdev)
{
struct fbc_priv *priv = container_of(cdev,
struct fbc_priv, cdev);
if (priv->active) {
fb_close(priv->sc);
priv->active = false;
return 0;
}
return -EINVAL;
}
static int set_font(struct param_d *p, void *vpriv) static int set_font(struct param_d *p, void *vpriv)
{ {
struct fbc_priv *priv = vpriv; struct fbc_priv *priv = vpriv;
@ -434,7 +492,8 @@ int register_fbconsole(struct fb_info *fb)
cdev->getc = fbc_getc; cdev->getc = fbc_getc;
cdev->devname = "fbconsole"; cdev->devname = "fbconsole";
cdev->devid = DEVICE_ID_DYNAMIC; cdev->devid = DEVICE_ID_DYNAMIC;
cdev->set_active = fbc_set_active; cdev->open = fbc_open;
cdev->close = fbc_close;
ret = console_register(cdev); ret = console_register(cdev);
if (ret) { if (ret) {

567
drivers/video/ssd1307fb.c Normal file
View File

@ -0,0 +1,567 @@
/*
* Driver for the Solomon SSD1307 OLED controller family
*
* Supports:
* - SSD1305 (untested)
* - SSD1306
* - SSD1309 (untested)
*
* The SSD1307 controller is currently unsupported as the PWM parts were not
* ported.
*
* Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>, Free Electrons
*
* Ported to barebox from linux v4.10
* Copyright (C) 2017 Pengutronix, Bastian Stender <kernel@pengutronix.de>
*
* Licensed under the GPLv2 or later.
*/
#include <common.h>
#include <init.h>
#include <fb.h>
#include <i2c/i2c.h>
#include <of_device.h>
#include <gpio.h>
#include <of_gpio.h>
#define SSD1307FB_DATA 0x40
#define SSD1307FB_COMMAND 0x80
#define SSD1307FB_SET_ADDRESS_MODE 0x20
#define SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL (0x00)
#define SSD1307FB_SET_ADDRESS_MODE_VERTICAL (0x01)
#define SSD1307FB_SET_ADDRESS_MODE_PAGE (0x02)
#define SSD1307FB_SET_COL_RANGE 0x21
#define SSD1307FB_SET_PAGE_RANGE 0x22
#define SSD1307FB_CONTRAST 0x81
#define SSD1307FB_CHARGE_PUMP 0x8d
#define SSD1307FB_SEG_REMAP_ON 0xa1
#define SSD1307FB_DISPLAY_OFF 0xae
#define SSD1307FB_SET_MULTIPLEX_RATIO 0xa8
#define SSD1307FB_DISPLAY_ON 0xaf
#define SSD1307FB_START_PAGE_ADDRESS 0xb0
#define SSD1307FB_SET_DISPLAY_OFFSET 0xd3
#define SSD1307FB_SET_CLOCK_FREQ 0xd5
#define SSD1307FB_SET_PRECHARGE_PERIOD 0xd9
#define SSD1307FB_SET_COM_PINS_CONFIG 0xda
#define SSD1307FB_SET_VCOMH 0xdb
struct ssd1307fb_deviceinfo {
u32 default_vcomh;
u32 default_dclk_div;
u32 default_dclk_frq;
int need_chargepump;
};
struct ssd1307fb_par {
u32 com_invdir;
u32 com_lrremap;
u32 com_offset;
u32 com_seq;
u32 contrast;
u32 dclk_div;
u32 dclk_frq;
const struct ssd1307fb_deviceinfo *device_info;
struct i2c_client *client;
u32 height;
struct fb_info *info;
u32 page_offset;
u32 prechargep1;
u32 prechargep2;
int reset;
u32 seg_remap;
u32 vcomh;
u32 width;
};
struct ssd1307fb_array {
u8 type;
u8 data[0];
};
static struct ssd1307fb_array *ssd1307fb_alloc_array(u32 len, u8 type)
{
struct ssd1307fb_array *array;
array = kzalloc(sizeof(struct ssd1307fb_array) + len, GFP_KERNEL);
if (!array)
return NULL;
array->type = type;
return array;
}
static int ssd1307fb_write_array(struct i2c_client *client,
struct ssd1307fb_array *array, u32 len)
{
int ret;
len += sizeof(struct ssd1307fb_array);
ret = i2c_master_send(client, (u8 *)array, len);
if (ret != len) {
dev_err(&client->dev, "Couldn't send I2C command.\n");
return ret;
}
return 0;
}
static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
{
struct ssd1307fb_array *array;
int ret;
array = ssd1307fb_alloc_array(1, SSD1307FB_COMMAND);
if (!array)
return -ENOMEM;
array->data[0] = cmd;
ret = ssd1307fb_write_array(client, array, 1);
kfree(array);
return ret;
}
static void ssd1307fb_update_display(struct ssd1307fb_par *par)
{
struct ssd1307fb_array *array;
u8 *vmem = par->info->screen_base;
int i, j, k;
array = ssd1307fb_alloc_array(par->width * par->height / 8,
SSD1307FB_DATA);
if (!array)
return;
/*
* The screen is divided in pages, each having a height of 8
* pixels, and the width of the screen. When sending a byte of
* data to the controller, it gives the 8 bits for the current
* column. I.e, the first byte are the 8 bits of the first
* column, then the 8 bits for the second column, etc.
*
*
* Representation of the screen, assuming it is 5 bits
* wide. Each letter-number combination is a bit that controls
* one pixel.
*
* A0 A1 A2 A3 A4
* B0 B1 B2 B3 B4
* C0 C1 C2 C3 C4
* D0 D1 D2 D3 D4
* E0 E1 E2 E3 E4
* F0 F1 F2 F3 F4
* G0 G1 G2 G3 G4
* H0 H1 H2 H3 H4
*
* If you want to update this screen, you need to send 5 bytes:
* (1) A0 B0 C0 D0 E0 F0 G0 H0
* (2) A1 B1 C1 D1 E1 F1 G1 H1
* (3) A2 B2 C2 D2 E2 F2 G2 H2
* (4) A3 B3 C3 D3 E3 F3 G3 H3
* (5) A4 B4 C4 D4 E4 F4 G4 H4
*/
for (i = 0; i < (par->height / 8); i++) {
for (j = 0; j < par->width; j++) {
u32 array_idx = i * par->width + j;
array->data[array_idx] = 0;
for (k = 0; k < 8; k++) {
u32 page_length = par->width * i * 8;
u32 index = page_length + (par->width * k + j);
u8 byte = *(vmem + index);
/* convert to 1 bit per pixel */
u8 bit = byte > 0;
array->data[array_idx] |= bit << k;
}
}
}
ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
kfree(array);
}
static void ssd1307fb_enable(struct fb_info *info)
{
struct ssd1307fb_par *par = info->priv;
ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
}
static void ssd1307fb_disable(struct fb_info *info)
{
struct ssd1307fb_par *par = info->priv;
ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_OFF);
}
static void ssd1307fb_flush(struct fb_info *info)
{
struct ssd1307fb_par *par = info->priv;
ssd1307fb_update_display(par);
}
static struct fb_ops ssd1307fb_ops = {
.fb_enable = ssd1307fb_enable,
.fb_disable = ssd1307fb_disable,
.fb_flush = ssd1307fb_flush,
};
static int ssd1307fb_init(struct ssd1307fb_par *par)
{
int ret;
u32 precharge, dclk, com_invdir, compins;
/* Set initial contrast */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, par->contrast);
if (ret < 0)
return ret;
/* Set segment re-map */
if (par->seg_remap) {
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SEG_REMAP_ON);
if (ret < 0)
return ret;
};
/* Set COM direction */
com_invdir = 0xc0 | (par->com_invdir & 0x1) << 3;
ret = ssd1307fb_write_cmd(par->client, com_invdir);
if (ret < 0)
return ret;
/* Set multiplex ratio value */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, par->height - 1);
if (ret < 0)
return ret;
/* set display offset value */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, par->com_offset);
if (ret < 0)
return ret;
/* Set clock frequency */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ);
if (ret < 0)
return ret;
dclk = ((par->dclk_div - 1) & 0xf) | (par->dclk_frq & 0xf) << 4;
ret = ssd1307fb_write_cmd(par->client, dclk);
if (ret < 0)
return ret;
/* Set precharge period in number of ticks from the internal clock */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD);
if (ret < 0)
return ret;
precharge = (par->prechargep1 & 0xf) | (par->prechargep2 & 0xf) << 4;
ret = ssd1307fb_write_cmd(par->client, precharge);
if (ret < 0)
return ret;
/* Set COM pins configuration */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG);
if (ret < 0)
return ret;
compins = 0x02 | !(par->com_seq & 0x1) << 4
| (par->com_lrremap & 0x1) << 5;
ret = ssd1307fb_write_cmd(par->client, compins);
if (ret < 0)
return ret;
/* Set VCOMH */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, par->vcomh);
if (ret < 0)
return ret;
/* Turn on the DC-DC Charge Pump */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client,
BIT(4) | (par->device_info->need_chargepump ? BIT(2) : 0));
if (ret < 0)
return ret;
/* Switch to horizontal addressing mode */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client,
SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
if (ret < 0)
return ret;
/* Set column range */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, 0x0);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, par->width - 1);
if (ret < 0)
return ret;
/* Set page range */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, 0x0);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client,
par->page_offset + (par->height / 8) - 1);
if (ret < 0)
return ret;
/* Turn on the display */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_DISPLAY_ON);
if (ret < 0)
return ret;
return 0;
}
static struct ssd1307fb_deviceinfo ssd1307fb_ssd1305_deviceinfo = {
.default_vcomh = 0x34,
.default_dclk_div = 1,
.default_dclk_frq = 7,
};
static struct ssd1307fb_deviceinfo ssd1307fb_ssd1306_deviceinfo = {
.default_vcomh = 0x20,
.default_dclk_div = 1,
.default_dclk_frq = 8,
.need_chargepump = 1,
};
static struct ssd1307fb_deviceinfo ssd1307fb_ssd1309_deviceinfo = {
.default_vcomh = 0x34,
.default_dclk_div = 1,
.default_dclk_frq = 10,
};
static const struct of_device_id ssd1307fb_of_match[] = {
{
.compatible = "solomon,ssd1305fb-i2c",
.data = (void *)&ssd1307fb_ssd1305_deviceinfo,
},
{
.compatible = "solomon,ssd1306fb-i2c",
.data = (void *)&ssd1307fb_ssd1306_deviceinfo,
},
{
.compatible = "solomon,ssd1309fb-i2c",
.data = (void *)&ssd1307fb_ssd1309_deviceinfo,
},
{},
};
static int ssd1307fb_probe(struct device_d *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct fb_info *info;
struct device_node *node = dev->device_node;
const struct of_device_id *match =
of_match_node(ssd1307fb_of_match, dev->device_node);
u32 vmem_size;
struct ssd1307fb_par *par;
struct ssd1307fb_array *array;
u8 *vmem;
int ret;
int i, j;
if (!node) {
dev_err(&client->dev, "No device tree data found!\n");
return -EINVAL;
}
info = xzalloc(sizeof(struct fb_info));
par = info->priv;
par->info = info;
par->client = client;
par->device_info = (struct ssd1307fb_deviceinfo *)match->data;
par->reset = of_get_named_gpio(node,
"reset-gpios", 0);
if (!gpio_is_valid(par->reset)) {
ret = par->reset;
if (ret != -EPROBE_DEFER)
dev_err(&client->dev,
"Couldn't get named gpio 'reset-gpios': %s.\n",
strerror(-ret));
goto fb_alloc_error;
}
ret = of_property_read_u32(node, "solomon,width", &par->width);
if (ret) {
dev_err(&client->dev,
"Couldn't find 'solomon,width' in device tree.\n");
goto panel_init_error;
}
ret = of_property_read_u32(node, "solomon,height", &par->height);
if (ret) {
dev_err(&client->dev,
"Couldn't find 'solomon,height' in device tree.\n");
goto panel_init_error;
}
ret = of_property_read_u32(node, "solomon,page-offset",
&par->page_offset);
if (ret) {
dev_err(&client->dev,
"Couldn't find 'solomon,page_offset' in device tree.\n");
goto panel_init_error;
}
if (of_property_read_u32(node, "solomon,com-offset", &par->com_offset))
par->com_offset = 0;
if (of_property_read_u32(node, "solomon,prechargep1",
&par->prechargep1))
par->prechargep1 = 2;
if (of_property_read_u32(node, "solomon,prechargep2",
&par->prechargep2))
par->prechargep2 = 2;
par->seg_remap = !of_property_read_bool(node,
"solomon,segment-no-remap");
par->com_seq = of_property_read_bool(node, "solomon,com-seq");
par->com_lrremap = of_property_read_bool(node, "solomon,com-lrremap");
par->com_invdir = of_property_read_bool(node, "solomon,com-invdir");
par->contrast = 127;
par->vcomh = par->device_info->default_vcomh;
/* Setup display timing */
par->dclk_div = par->device_info->default_dclk_div;
par->dclk_frq = par->device_info->default_dclk_frq;
vmem_size = par->width * par->height;
vmem = malloc(vmem_size);
if (!vmem) {
dev_err(&client->dev, "Couldn't allocate graphical memory.\n");
ret = -ENOMEM;
goto fb_alloc_error;
}
info->fbops = &ssd1307fb_ops;
info->line_length = par->width;
info->xres = par->width;
info->yres = par->height;
/* emulate 8 bit per pixel */
info->bits_per_pixel = 8;
info->red.length = 3;
info->red.offset = 0;
info->green.length = 3;
info->green.offset = 0;
info->blue.length = 2;
info->blue.offset = 0;
info->screen_base = (u8 __force __iomem *)vmem;
ret = gpio_request_one(par->reset,
GPIOF_OUT_INIT_HIGH,
"oled-reset");
if (ret) {
dev_err(&client->dev,
"failed to request gpio %d: %d\n",
par->reset, ret);
goto reset_oled_error;
}
i2c_set_clientdata(client, info);
/* Reset the screen */
gpio_set_value(par->reset, 0);
udelay(4);
gpio_set_value(par->reset, 1);
udelay(4);
ret = ssd1307fb_init(par);
if (ret)
goto reset_oled_error;
ret = register_framebuffer(info);
if (ret) {
dev_err(&client->dev, "Couldn't register the framebuffer\n");
goto panel_init_error;
}
/* clear display */
array = ssd1307fb_alloc_array(par->width * par->height / 8,
SSD1307FB_DATA);
if (!array)
return -ENOMEM;
for (i = 0; i < (par->height / 8); i++) {
for (j = 0; j < par->width; j++) {
u32 array_idx = i * par->width + j;
array->data[array_idx] = 0;
}
}
ssd1307fb_write_array(par->client, array, par->width * par->height / 8);
kfree(array);
dev_info(&client->dev,
"ssd1307 framebuffer device registered, using %d bytes of video memory\n",
vmem_size);
return 0;
panel_init_error:
reset_oled_error:
fb_alloc_error:
free(info);
return ret;
}
static struct driver_d ssd1307fb_driver = {
.name = "ssd1307fb",
.probe = ssd1307fb_probe,
.of_compatible = DRV_OF_COMPAT(ssd1307fb_of_match),
};
static int ssd1307_init(void)
{
i2c_driver_register(&ssd1307fb_driver);
return 0;
}
device_initcall(ssd1307_init);

View File

@ -44,7 +44,8 @@ struct console_device {
int (*setbrg)(struct console_device *cdev, int baudrate); int (*setbrg)(struct console_device *cdev, int baudrate);
void (*flush)(struct console_device *cdev); void (*flush)(struct console_device *cdev);
int (*set_mode)(struct console_device *cdev, enum console_mode mode); int (*set_mode)(struct console_device *cdev, enum console_mode mode);
int (*set_active)(struct console_device *cdev, unsigned active); int (*open)(struct console_device *cdev);
int (*close)(struct console_device *cdev);
char *devname; char *devname;
int devid; int devid;
@ -54,10 +55,15 @@ struct console_device {
unsigned char f_active; unsigned char f_active;
char active[4]; char active[4];
unsigned int open_count;
unsigned int baudrate; unsigned int baudrate;
unsigned int baudrate_param; unsigned int baudrate_param;
const char *linux_console_name; const char *linux_console_name;
struct cdev devfs;
struct file_operations fops;
}; };
int console_register(struct console_device *cdev); int console_register(struct console_device *cdev);
@ -75,6 +81,8 @@ extern int barebox_loglevel;
struct console_device *console_get_first_active(void); struct console_device *console_get_first_active(void);
int console_open(struct console_device *cdev);
int console_close(struct console_device *cdev);
int console_set_active(struct console_device *cdev, unsigned active); int console_set_active(struct console_device *cdev, unsigned active);
unsigned console_get_active(struct console_device *cdev); unsigned console_get_active(struct console_device *cdev);
int console_set_baudrate(struct console_device *cdev, unsigned baudrate); int console_set_baudrate(struct console_device *cdev, unsigned baudrate);

View File

@ -86,6 +86,7 @@ struct fb_ops {
void (*fb_enable)(struct fb_info *info); void (*fb_enable)(struct fb_info *info);
void (*fb_disable)(struct fb_info *info); void (*fb_disable)(struct fb_info *info);
int (*fb_activate_var)(struct fb_info *info); int (*fb_activate_var)(struct fb_info *info);
void (*fb_flush)(struct fb_info *info);
}; };
/* /*
@ -152,6 +153,7 @@ int register_framebuffer(struct fb_info *info);
int fb_enable(struct fb_info *info); int fb_enable(struct fb_info *info);
int fb_disable(struct fb_info *info); int fb_disable(struct fb_info *info);
void fb_flush(struct fb_info *info);
#define FBIOGET_SCREENINFO _IOR('F', 1, loff_t) #define FBIOGET_SCREENINFO _IOR('F', 1, loff_t)
#define FBIO_ENABLE _IO('F', 2) #define FBIO_ENABLE _IO('F', 2)

View File

@ -14,6 +14,9 @@ config FONT_8x16
This is the "high resolution" font for the VGA frame buffer (the one This is the "high resolution" font for the VGA frame buffer (the one
provided by the VGA text console 80x25 mode). provided by the VGA text console 80x25 mode).
config FONT_8x8
bool "VGA 8x8 font"
config FONT_7x14 config FONT_7x14
bool "7x14 font" bool "7x14 font"
@ -27,6 +30,7 @@ config FONT_CUSTOM_16X
config FONT_AUTOSELECT config FONT_AUTOSELECT
def_bool y def_bool y
depends on !FONT_MINI_8x8
depends on !FONT_MINI_4x6 depends on !FONT_MINI_4x6
depends on !FONT_7x14 depends on !FONT_7x14
select FONT_8x16 select FONT_8x16

View File

@ -3,6 +3,7 @@
font-objs := fonts.o font-objs := fonts.o
font-objs-$(CONFIG_FONT_8x16) += font_8x16.o font-objs-$(CONFIG_FONT_8x16) += font_8x16.o
font-objs-$(CONFIG_FONT_8x8) += font_8x8.o
font-objs-$(CONFIG_FONT_7x14) += font_7x14.o font-objs-$(CONFIG_FONT_7x14) += font_7x14.o
font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o
font-objs-$(CONFIG_FONT_CUSTOM_16X)+= font_custom_16x.o font-objs-$(CONFIG_FONT_CUSTOM_16X)+= font_custom_16x.o

2587
lib/fonts/font_8x8.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,9 @@ static void __illuminate(struct fb_info *info,
{ {
void *pixel; void *pixel;
if (x < 0 || y < 0 || x >= info->xres || y >= info->yres)
return;
pixel = fb_get_screen_base(info); pixel = fb_get_screen_base(info);
pixel += y * info->line_length + x * (info->bits_per_pixel >> 3); pixel += y * info->line_length + x * (info->bits_per_pixel >> 3);

View File

@ -132,6 +132,7 @@ void gu_set_pixel(struct fb_info *info, void *adr, u32 px)
{ {
switch (info->bits_per_pixel) { switch (info->bits_per_pixel) {
case 8: case 8:
*(u8 *)adr = px & 0xff;
break; break;
case 16: case 16:
*(u16 *)adr = px & 0xffff; *(u16 *)adr = px & 0xffff;
@ -276,8 +277,6 @@ struct screen *fb_open(const char * fbdev)
if (fd < 0) if (fd < 0)
return ERR_PTR(fd); return ERR_PTR(fd);
info = xzalloc(sizeof(*info));
ret = ioctl(fd, FBIOGET_SCREENINFO, &info); ret = ioctl(fd, FBIOGET_SCREENINFO, &info);
if (ret) { if (ret) {
goto failed_screeninfo; goto failed_screeninfo;
@ -290,7 +289,6 @@ struct screen *fb_open(const char * fbdev)
} }
sc->fd = fd; sc->fd = fd;
sc->info = info;
return sc; return sc;

View File

@ -105,19 +105,11 @@ static void nc_putc(struct console_device *cdev, char c)
priv->busy = 0; priv->busy = 0;
} }
static int nc_set_active(struct console_device *cdev, unsigned flags) static int nc_open(struct console_device *cdev)
{ {
struct nc_priv *priv = container_of(cdev, struct nc_priv *priv = container_of(cdev,
struct nc_priv, cdev); struct nc_priv, cdev);
if (priv->con) {
net_unregister(priv->con);
priv->con = NULL;
}
if (!flags)
return 0;
if (!priv->port) { if (!priv->port) {
pr_err("port not set\n"); pr_err("port not set\n");
return -EINVAL; return -EINVAL;
@ -142,6 +134,20 @@ static int nc_set_active(struct console_device *cdev, unsigned flags)
return 0; return 0;
} }
static int nc_close(struct console_device *cdev)
{
struct nc_priv *priv = container_of(cdev,
struct nc_priv, cdev);
if (priv->con) {
net_unregister(priv->con);
priv->con = NULL;
return 0;
}
return -EINVAL;
}
static int netconsole_init(void) static int netconsole_init(void)
{ {
struct nc_priv *priv; struct nc_priv *priv;
@ -155,7 +161,8 @@ static int netconsole_init(void)
cdev->getc = nc_getc; cdev->getc = nc_getc;
cdev->devname = "netconsole"; cdev->devname = "netconsole";
cdev->devid = DEVICE_ID_SINGLE; cdev->devid = DEVICE_ID_SINGLE;
cdev->set_active = nc_set_active; cdev->open = nc_open;
cdev->close = nc_close;
g_priv = priv; g_priv = priv;