Commit e0c84537 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fbdev-3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux

Pull fbdev changes from Tomi Valkeinen:

 - omapdss: add DRA7xxx SoC support

 - fbdev: support DMT (Display Monitor Timing) calculation

* tag 'fbdev-3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (40 commits)
  omapfb: Return error code when applying overlay settings fails
  OMAPDSS: DPI: DRA7xx support
  OMAPDSS: HDMI: Add DRA7xx support
  OMAPDSS: DISPC: program dispc polarities to control module
  OMAPDSS: DISPC: Add DRA7xx support
  OMAPDSS: Add Video PLLs for DRA7xx
  OMAPDSS: Add functions for external control of PLL
  OMAPDSS: DSS: Add DRA7xx base support
  Doc/DT: Add DT binding doc for DRA7xx DSS
  OMAPDSS: add define for DRA7xx HW version
  OMAPDSS: encoder-tpd12s015: Fix race issue with LS_OE
  OMAPDSS: OMAP5: fix digit output's allowed mgrs
  OMAPDSS: constify port arrays
  OMAPDSS: PLL: add dss_pll_wait_reset_done()
  OMAPDSS: Add enum dss_pll_id
  video: fbdev: fix sys_copyarea
  video/mmpfb: allow modular build
  fb: via: turn gpiolib and i2c selects into dependencies
  fbdev: ssd1307fb: return proper error code if write command fails
  fbdev: fix CVT vertical front and back porch values
  ...
parents a323ae93 d6c2152b
Texas Instruments DRA7x Display Subsystem
=========================================
See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
description about OMAP Display Subsystem bindings.
DSS Core
--------
Required properties:
- compatible: "ti,dra7-dss"
- reg: address and length of the register spaces for 'dss'
- ti,hwmods: "dss_core"
- clocks: handle to fclk
- clock-names: "fck"
- syscon: phandle to control module core syscon node
Optional properties:
Some DRA7xx SoCs have one dedicated video PLL, some have two. These properties
can be used to describe the video PLLs:
- reg: address and length of the register spaces for 'pll1_clkctrl',
'pll1', 'pll2_clkctrl', 'pll2'
- clocks: handle to video1 pll clock and video2 pll clock
- clock-names: "video1_clk" and "video2_clk"
Required nodes:
- DISPC
Optional nodes:
- DSS Submodules: HDMI
- Video port for DPI output
DPI Endpoint required properties:
- data-lines: number of lines used
DISPC
-----
Required properties:
- compatible: "ti,dra7-dispc"
- reg: address and length of the register space
- ti,hwmods: "dss_dispc"
- interrupts: the DISPC interrupt
- clocks: handle to fclk
- clock-names: "fck"
HDMI
----
Required properties:
- compatible: "ti,dra7-hdmi"
- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy',
'core'
- reg-names: "wp", "pll", "phy", "core"
- interrupts: the HDMI interrupt line
- ti,hwmods: "dss_hdmi"
- vdda-supply: vdda power supply
- clocks: handles to fclk and pll clock
- clock-names: "fck", "sys_clk"
Optional nodes:
- Video port for HDMI output
HDMI Endpoint optional properties:
- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-,
D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7)
OPA362 analog video amplifier
Required properties:
- compatible: "ti,opa362"
- enable-gpios: enable/disable output gpio
Required node:
- Video port 0 for opa362 input
- Video port 1 for opa362 output
Example:
tv_amp: opa362 {
compatible = "ti,opa362";
enable-gpios = <&gpio1 23 0>; /* GPIO to enable video out amplifier */
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
opa_in: endpoint@0 {
remote-endpoint = <&venc_out>;
};
};
port@1 {
reg = <1>;
opa_out: endpoint@0 {
remote-endpoint = <&tv_connector_in>;
};
};
};
};
......@@ -77,18 +77,22 @@ config DUMMY_CONSOLE
config DUMMY_CONSOLE_COLUMNS
int "Initial number of console screen columns"
depends on PARISC && DUMMY_CONSOLE
default "160"
depends on DUMMY_CONSOLE && !ARM
default 160 if PARISC
default 80
help
The default value is 160, which should fit a 1280x1024 monitor.
On PA-RISC, the default value is 160, which should fit a 1280x1024
monitor.
Select 80 if you use a 640x480 resolution by default.
config DUMMY_CONSOLE_ROWS
int "Initial number of console screen rows"
depends on PARISC && DUMMY_CONSOLE
default "64"
depends on DUMMY_CONSOLE && !ARM
default 64 if PARISC
default 25
help
The default value is 64, which should fit a 1280x1024 monitor.
On PA-RISC, the default value is 64, which should fit a 1280x1024
monitor.
Select 25 if you use a 640x480 resolution by default.
config FRAMEBUFFER_CONSOLE
......
......@@ -20,13 +20,10 @@
#if defined(__arm__)
#define DUMMY_COLUMNS screen_info.orig_video_cols
#define DUMMY_ROWS screen_info.orig_video_lines
#elif defined(__hppa__)
#else
/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */
#define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS
#define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS
#else
#define DUMMY_COLUMNS 80
#define DUMMY_ROWS 25
#endif
static const char *dummycon_startup(void)
......
......@@ -146,9 +146,6 @@ static const struct consw fb_con;
static int fbcon_set_origin(struct vc_data *);
#define CURSOR_DRAW_DELAY (1)
static int vbl_cursor_cnt;
static int fbcon_cursor_noblink;
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
......@@ -1329,7 +1326,6 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
}
static int scrollback_phys_max = 0;
......
......@@ -1530,13 +1530,11 @@ config FB_SIS_315
config FB_VIA
tristate "VIA UniChrome (Pro) and Chrome9 display support"
depends on FB && PCI && X86
depends on FB && PCI && X86 && GPIOLIB && I2C
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select I2C_ALGOBIT
select I2C
select GPIOLIB
help
This is the frame buffer device driver for Graphics chips of VIA
UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
......@@ -2151,7 +2149,6 @@ config FB_PS3
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
---help---
Include support for the virtual frame buffer in the PS3 platform.
......
......@@ -3948,7 +3948,7 @@ static struct notifier_block atyfb_reboot_notifier = {
.notifier_call = atyfb_reboot_notify,
};
static const struct dmi_system_id atyfb_reboot_ids[] = {
static const struct dmi_system_id atyfb_reboot_ids[] __initconst = {
{
.ident = "HP OmniBook 500",
.matches = {
......@@ -3960,6 +3960,7 @@ static const struct dmi_system_id atyfb_reboot_ids[] = {
{ }
};
static bool registered_notifier = false;
static int __init atyfb_init(void)
{
......@@ -3982,15 +3983,17 @@ static int __init atyfb_init(void)
if (err1 && err2)
return -ENODEV;
if (dmi_check_system(atyfb_reboot_ids))
if (dmi_check_system(atyfb_reboot_ids)) {
register_reboot_notifier(&atyfb_reboot_notifier);
registered_notifier = true;
}
return 0;
}
static void __exit atyfb_exit(void)
{
if (dmi_check_system(atyfb_reboot_ids))
if (registered_notifier)
unregister_reboot_notifier(&atyfb_reboot_notifier);
#ifdef CONFIG_PCI
......
......@@ -369,9 +369,9 @@ int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb)
cvt.h_back_porch = cvt.hblank/2 + cvt.h_margin;
cvt.h_front_porch = cvt.hblank - cvt.hsync - cvt.h_back_porch +
2 * cvt.h_margin;
cvt.v_back_porch = 3 + cvt.v_margin;
cvt.v_front_porch = cvt.vtotal - cvt.yres/cvt.interlace -
cvt.v_back_porch - cvt.vsync;
cvt.v_front_porch = 3 + cvt.v_margin;
cvt.v_back_porch = cvt.vtotal - cvt.yres/cvt.interlace -
cvt.v_front_porch - cvt.vsync;
fb_cvt_print_name(&cvt);
fb_cvt_convert_to_mode(&cvt, mode);
......
......@@ -496,56 +496,71 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
}
static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
int ver, int rev)
int ver, int rev, const struct fb_monspecs *specs)
{
int xres, yres = 0, refresh, ratio, i;
xres = (block[0] + 31) * 8;
if (xres <= 256)
return 0;
int i;
ratio = (block[1] & 0xc0) >> 6;
switch (ratio) {
case 0:
/* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
if (ver < 1 || (ver == 1 && rev < 3))
yres = xres;
else
yres = (xres * 10)/16;
break;
case 1:
yres = (xres * 3)/4;
break;
case 2:
yres = (xres * 4)/5;
break;
case 3:
yres = (xres * 9)/16;
break;
for (i = 0; i < DMT_SIZE; i++) {
u32 std_2byte_code = block[0] << 8 | block[1];
if (std_2byte_code == dmt_modes[i].std_2byte_code)
break;
}
refresh = (block[1] & 0x3f) + 60;
DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
for (i = 0; i < VESA_MODEDB_SIZE; i++) {
if (vesa_modes[i].xres == xres &&
vesa_modes[i].yres == yres &&
vesa_modes[i].refresh == refresh) {
*mode = vesa_modes[i];
mode->flag |= FB_MODE_IS_STANDARD;
return 1;
if (i < DMT_SIZE && dmt_modes[i].mode) {
/* DMT mode found */
*mode = *dmt_modes[i].mode;
mode->flag |= FB_MODE_IS_STANDARD;
DPRINTK(" DMT id=%d\n", dmt_modes[i].dmt_id);
} else {
int xres, yres = 0, refresh, ratio;
xres = (block[0] + 31) * 8;
if (xres <= 256)
return 0;
ratio = (block[1] & 0xc0) >> 6;
switch (ratio) {
case 0:
/* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
if (ver < 1 || (ver == 1 && rev < 3))
yres = xres;
else
yres = (xres * 10)/16;
break;
case 1:
yres = (xres * 3)/4;
break;
case 2:
yres = (xres * 4)/5;
break;
case 3:
yres = (xres * 9)/16;
break;
}
refresh = (block[1] & 0x3f) + 60;
DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
calc_mode_timings(xres, yres, refresh, mode);
}
calc_mode_timings(xres, yres, refresh, mode);
/* Check the mode we got is within valid spec of the monitor */
if (specs && specs->dclkmax
&& PICOS2KHZ(mode->pixclock) * 1000 > specs->dclkmax) {
DPRINTK(" mode exceed max DCLK\n");
return 0;
}
return 1;
}
static int get_dst_timing(unsigned char *block,
struct fb_videomode *mode, int ver, int rev)
static int get_dst_timing(unsigned char *block, struct fb_videomode *mode,
int ver, int rev, const struct fb_monspecs *specs)
{
int j, num = 0;
for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
num += get_std_timing(block, &mode[num], ver, rev);
num += get_std_timing(block, &mode[num], ver, rev, specs);
return num;
}
......@@ -601,7 +616,8 @@ static void get_detailed_timing(unsigned char *block,
* This function builds a mode database using the contents of the EDID
* data
*/
static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
const struct fb_monspecs *specs)
{
struct fb_videomode *mode, *m;
unsigned char *block;
......@@ -643,12 +659,13 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
DPRINTK(" Standard Timings\n");
block = edid + STD_TIMING_DESCRIPTIONS_START;
for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
num += get_std_timing(block, &mode[num], ver, rev);
num += get_std_timing(block, &mode[num], ver, rev, specs);
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
num += get_dst_timing(block + 5, &mode[num], ver, rev);
num += get_dst_timing(block + 5, &mode[num],
ver, rev, specs);
}
/* Yikes, EDID data is totally useless */
......@@ -707,7 +724,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
int num_modes, hz, hscan, pixclock;
int vtotal, htotal;
modes = fb_create_modedb(edid, &num_modes);
modes = fb_create_modedb(edid, &num_modes, specs);
if (!modes) {
DPRINTK("None Available\n");
return 1;
......@@ -964,7 +981,7 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
DPRINTK(" Display Characteristics:\n");
get_monspecs(edid, specs);
specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
specs->modedb = fb_create_modedb(edid, &specs->modedb_len, specs);
/*
* Workaround for buggy EDIDs that sets that the first
......
......@@ -468,8 +468,119 @@ const struct fb_videomode vesa_modes[] = {
/* 33 1920x1440-75 VESA */
{ NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 34 1920x1200-60 RB VESA */
{ NULL, 60, 1920, 1200, 6493, 80, 48, 26, 3, 32, 6,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 35 1920x1200-60 VESA */
{ NULL, 60, 1920, 1200, 5174, 336, 136, 36, 3, 200, 6,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 36 1920x1200-75 VESA */
{ NULL, 75, 1920, 1200, 4077, 344, 136, 46, 3, 208, 6,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 37 1920x1200-85 VESA */
{ NULL, 85, 1920, 1200, 3555, 352, 144, 53, 3, 208, 6,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 38 2560x1600-60 RB VESA */
{ NULL, 60, 2560, 1600, 3724, 80, 48, 37, 3, 32, 6,
FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 39 2560x1600-60 VESA */
{ NULL, 60, 2560, 1600, 2869, 472, 192, 49, 3, 280, 6,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 40 2560x1600-75 VESA */
{ NULL, 75, 2560, 1600, 2256, 488, 208, 63, 3, 280, 6,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 41 2560x1600-85 VESA */
{ NULL, 85, 2560, 1600, 1979, 488, 208, 73, 3, 280, 6,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 42 2560x1600-120 RB VESA */
{ NULL, 120, 2560, 1600, 1809, 80, 48, 85, 3, 32, 6,
FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
};
EXPORT_SYMBOL(vesa_modes);
const struct dmt_videomode dmt_modes[DMT_SIZE] = {
{ 0x01, 0x0000, 0x000000, &vesa_modes[0] },
{ 0x02, 0x3119, 0x000000, &vesa_modes[1] },
{ 0x03, 0x0000, 0x000000, &vesa_modes[2] },
{ 0x04, 0x3140, 0x000000, &vesa_modes[3] },
{ 0x05, 0x314c, 0x000000, &vesa_modes[4] },
{ 0x06, 0x314f, 0x000000, &vesa_modes[5] },
{ 0x07, 0x3159, 0x000000, &vesa_modes[6] },
{ 0x08, 0x0000, 0x000000, &vesa_modes[7] },
{ 0x09, 0x4540, 0x000000, &vesa_modes[8] },
{ 0x0a, 0x454c, 0x000000, &vesa_modes[9] },
{ 0x0b, 0x454f, 0x000000, &vesa_modes[10] },
{ 0x0c, 0x4559, 0x000000, &vesa_modes[11] },
{ 0x0d, 0x0000, 0x000000, NULL },
{ 0x0e, 0x0000, 0x000000, NULL },
{ 0x0f, 0x0000, 0x000000, &vesa_modes[12] },
{ 0x10, 0x6140, 0x000000, &vesa_modes[13] },
{ 0x11, 0x614a, 0x000000, &vesa_modes[14] },
{ 0x12, 0x614f, 0x000000, &vesa_modes[15] },
{ 0x13, 0x6159, 0x000000, &vesa_modes[16] },
{ 0x14, 0x0000, 0x000000, NULL },
{ 0x15, 0x714f, 0x000000, &vesa_modes[17] },
{ 0x16, 0x0000, 0x7f1c21, NULL },
{ 0x17, 0x0000, 0x7f1c28, NULL },
{ 0x18, 0x0000, 0x7f1c44, NULL },
{ 0x19, 0x0000, 0x7f1c62, NULL },
{ 0x1a, 0x0000, 0x000000, NULL },
{ 0x1b, 0x0000, 0x8f1821, NULL },
{ 0x1c, 0x8100, 0x8f1828, NULL },
{ 0x1d, 0x810f, 0x8f1844, NULL },
{ 0x1e, 0x8119, 0x8f1862, NULL },
{ 0x1f, 0x0000, 0x000000, NULL },
{ 0x20, 0x8140, 0x000000, &vesa_modes[18] },
{ 0x21, 0x8159, 0x000000, &vesa_modes[19] },
{ 0x22, 0x0000, 0x000000, NULL },
{ 0x23, 0x8180, 0x000000, &vesa_modes[20] },
{ 0x24, 0x818f, 0x000000, &vesa_modes[21] },
{ 0x25, 0x8199, 0x000000, &vesa_modes[22] },
{ 0x26, 0x0000, 0x000000, NULL },
{ 0x27, 0x0000, 0x000000, NULL },
{ 0x28, 0x0000, 0x000000, NULL },
{ 0x29, 0x0000, 0x0c2021, NULL },
{ 0x2a, 0x9040, 0x0c2028, NULL },
{ 0x2b, 0x904f, 0x0c2044, NULL },
{ 0x2c, 0x9059, 0x0c2062, NULL },
{ 0x2d, 0x0000, 0x000000, NULL },
{ 0x2e, 0x9500, 0xc11821, NULL },
{ 0x2f, 0x9500, 0xc11828, NULL },
{ 0x30, 0x950f, 0xc11844, NULL },
{ 0x31, 0x9519, 0xc11868, NULL },
{ 0x32, 0x0000, 0x000000, NULL },
{ 0x33, 0xa940, 0x000000, &vesa_modes[23] },
{ 0x34, 0xa945, 0x000000, &vesa_modes[24] },
{ 0x35, 0xa94a, 0x000000, &vesa_modes[25] },
{ 0x36, 0xa94f, 0x000000, &vesa_modes[26] },
{ 0x37, 0xa959, 0x000000, &vesa_modes[27] },
{ 0x38, 0x0000, 0x000000, NULL },
{ 0x39, 0x0000, 0x0c2821, NULL },
{ 0x3a, 0xb300, 0x0c2828, NULL },
{ 0x3b, 0xb30f, 0x0c2844, NULL },
{ 0x3c, 0xb319, 0x0c2868, NULL },
{ 0x3d, 0x0000, 0x000000, NULL },
{ 0x3e, 0xc140, 0x000000, &vesa_modes[28] },
{ 0x3f, 0xc14f, 0x000000, &vesa_modes[29] },
{ 0x40, 0x0000, 0x000000, NULL},
{ 0x41, 0xc940, 0x000000, &vesa_modes[30] },
{ 0x42, 0xc94f, 0x000000, &vesa_modes[31] },
{ 0x43, 0x0000, 0x000000, NULL },
{ 0x44, 0x0000, 0x572821, &vesa_modes[34] },
{ 0x45, 0xd100, 0x572828, &vesa_modes[35] },
{ 0x46, 0xd10f, 0x572844, &vesa_modes[36] },
{ 0x47, 0xd119, 0x572862, &vesa_modes[37] },
{ 0x48, 0x0000, 0x000000, NULL },
{ 0x49, 0xd140, 0x000000, &vesa_modes[32] },
{ 0x4a, 0xd14f, 0x000000, &vesa_modes[33] },
{ 0x4b, 0x0000, 0x000000, NULL },
{ 0x4c, 0x0000, 0x1f3821, &vesa_modes[38] },
{ 0x4d, 0x0000, 0x1f3828, &vesa_modes[39] },
{ 0x4e, 0x0000, 0x1f3844, &vesa_modes[40] },
{ 0x4f, 0x0000, 0x1f3862, &vesa_modes[41] },
{ 0x50, 0x0000, 0x000000, &vesa_modes[42] },
};
EXPORT_SYMBOL(dmt_modes);
#endif /* CONFIG_FB_MODE_HELPERS */
/**
......
......@@ -25,8 +25,8 @@
*/
static void
bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
const unsigned long *src, int src_idx, int bits, unsigned n)
bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
const unsigned long *src, unsigned src_idx, int bits, unsigned n)
{
unsigned long first, last;
int const shift = dst_idx-src_idx;
......@@ -86,15 +86,15 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
first &= last;
if (shift > 0) {
/* Single source word */
*dst = comp(*src >> right, *dst, first);
*dst = comp(*src << left, *dst, first);
} else if (src_idx+n <= bits) {
/* Single source word */
*dst = comp(*src << left, *dst, first);
*dst = comp(*src >> right, *dst, first);
} else {
/* 2 source words */
d0 = *src++;
d1 = *src;
*dst = comp(d0 << left | d1 >> right, *dst,
*dst = comp(d0 >> right | d1 << left, *dst,
first);
}
} else {
......@@ -109,13 +109,14 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
/* Leading bits */
if (shift > 0) {
/* Single source word */
*dst = comp(d0 >> right, *dst, first);
*dst = comp(d0 << left, *dst, first);
dst++;
n -= bits - dst_idx;
} else {
/* 2 source words */
d1 = *src++;
*dst = comp(d0 << left | *dst >> right, *dst, first);
*dst = comp(d0 >> right | d1 << left, *dst,
first);
d0 = d1;
dst++;
n -= bits - dst_idx;
......@@ -126,36 +127,36 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
n /= bits;
while (n >= 4) {
d1 = *src++;
*dst++ = d0 << left | d1 >> right;
*dst++ = d0 >> right | d1 << left;
d0 = d1;
d1 = *src++;
*dst++ = d0 << left | d1 >> right;
*dst++ = d0 >> right | d1 << left;
d0 = d1;
d1 = *src++;
*dst++ = d0 << left | d1 >> right;
*dst++ = d0 >> right | d1 << left;
d0 = d1;
d1 = *src++;
*dst++ = d0 << left | d1 >> right;
*dst++ = d0 >> right | d1 << left;
d0 = d1;
n -= 4;
}
while (n--) {
d1 = *src++;
*dst++ = d0 << left | d1 >> right;
*dst++ = d0 >> right | d1 << left;
d0 = d1;
}
/* Trailing bits */
if (last) {
if (m <= right) {
if (m) {
if (m <= bits - right) {
/* Single source word */
*dst = comp(d0 << left, *dst, last);
d0 >>= right;
} else {
/* 2 source words */
d1 = *src;
*dst = comp(d0 << left | d1 >> right,
*dst, last);
d0 = d0 >> right | d1 << left;
}
*dst = comp(d0, *dst, last);
}
}
}
......@@ -166,40 +167,35 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
*/
static void
bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
const unsigned long *src, int src_idx, int bits, unsigned n)
bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
const unsigned long *src, unsigned src_idx, unsigned bits,
unsigned n)
{
unsigned long first, last;
int shift;
dst += (n-1)/bits;
src += (n-1)/bits;
if ((n-1) % bits) {
dst_idx += (n-1) % bits;
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= bits - 1;
src_idx += (n-1) % bits;
src += src_idx >> (ffs(bits) - 1);
src_idx &= bits - 1;
}
dst += (dst_idx + n - 1) / bits;
src += (src_idx + n - 1) / bits;
dst_idx = (dst_idx + n - 1) % bits;
src_idx = (src_idx + n - 1) % bits;
shift = dst_idx-src_idx;
first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx);
last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits)));
first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits);
last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits);
if (!shift) {
/* Same alignment for source and dest */
if ((unsigned long)dst_idx+1 >= n) {
/* Single word */
if (last)
first &= last;
*dst = comp(*src, *dst, first);
if (first)
last &= first;
*dst = comp(*src, *dst, last);
} else {
/* Multiple destination words */
/* Leading bits */
if (first != ~0UL) {
if (first) {
*dst = comp(*src, *dst, first);
dst--;
src--;
......@@ -222,29 +218,29 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
while (n--)
*dst-- = *src--;
/* Trailing bits */
if (last)
if (last != -1UL)
*dst = comp(*src, *dst, last);
}
} else {
/* Different alignment for source and dest */
int const left = -shift & (bits-1);
int const right = shift & (bits-1);
int const left = shift & (bits-1);
int const right = -shift & (bits-1);
if ((unsigned long)dst_idx+1 >= n) {
/* Single destination word */
if (last)
first &= last;
if (first)
last &= first;
if (shift < 0) {
/* Single source word */
*dst = comp(*src << left, *dst, first);
*dst = comp(*src >> right, *dst, last);
} else if (1+(unsigned long)src_idx >= n) {
/* Single source word */
*dst = comp(*src >> right, *dst, first);
*dst = comp(*src << left, *dst, last);
} else {
/* 2 source words */
*dst = comp(*src >> right | *(src-1) << left,
*dst, first);
*dst = comp(*src << left | *(src-1) >> right,
*dst, last);
}
} else {
/* Multiple destination words */
......@@ -261,14 +257,18 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
/* Leading bits */
if (shift < 0) {
/* Single source word */
*dst = comp(d0 << left, *dst, first);
d1 = d0;
d0 >>= right;
} else {
/* 2 source words */
d1 = *src--;
*dst = comp(d0 >> right | d1 << left, *dst,
first);
d0 = d1;
d0 = d0 << left | d1 >> right;
}
if (!first)
*dst = d0;
else
*dst = comp(d0, *dst, first);
d0 = d1;
dst--;
n -= dst_idx+1;
......@@ -277,36 +277,36 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
n /= bits;
while (n >= 4) {
d1 = *src--;
*dst-- = d0 >> right | d1 << left;
*dst-- = d0 << left | d1 >> right;
d0 = d1;
d1 = *src--;
*dst-- = d0 >> right | d1 << left;
*dst-- = d0 << left | d1 >> right;
d0 = d1;
d1 = *src--;
*dst-- = d0 >> right | d1 << left;
*dst-- = d0 << left | d1 >> right;
d0 = d1;
d1 = *src--;
*dst-- = d0 >> right | d1 << left;
*dst-- = d0 << left | d1 >> right;
d0 = d1;
n -= 4;
}
while (n--) {
d1 = *src--;
*dst-- = d0 >> right | d1 << left;
*dst-- = d0 << left | d1 >> right;
d0 = d1;
}
/* Trailing bits */
if (last) {
if (m <= left) {
if (m) {
if (m <= bits - left) {
/* Single source word */
*dst = comp(d0 >> right, *dst, last);
d0 <<= left;
} else {
/* 2 source words */
d1 = *src;
*dst = comp(d0 >> right | d1 << left,
*dst, last);
d0 = d0 << left | d1 >> right;
}
*dst = comp(d0, *dst, last);
}
}
}
......@@ -317,9 +317,9 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
u32 height = area->height, width = area->width;
unsigned long const bits_per_line = p->fix.line_length*8u;
unsigned long *dst = NULL, *src = NULL;
unsigned long *base = NULL;
int bits = BITS_PER_LONG, bytes = bits >> 3;
int dst_idx = 0, src_idx = 0, rev_copy = 0;
unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
if (p->state != FBINFO_STATE_RUNNING)
return;
......@@ -334,8 +334,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
/* split the base of the framebuffer into a long-aligned address and
the index of the first bit */
dst = src = (unsigned long *)((unsigned long)p->screen_base &
~(bytes-1));
base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
/* add offset of source and target area */
dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
......@@ -348,20 +347,14 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
while (height--) {
dst_idx -= bits_per_line;
src_idx -= bits_per_line;
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= (bytes - 1);
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
base + (src_idx / bits), src_idx % bits, bits,
width*p->var.bits_per_pixel);
}
} else {
while (height--) {
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= (bytes - 1);
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
bitcpy(p, dst, dst_idx, src, src_idx, bits,
bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
base + (src_idx / bits), src_idx % bits, bits,
width*p->var.bits_per_pixel);
dst_idx += bits_per_line;
src_idx += bits_per_line;
......
......@@ -374,10 +374,8 @@ static int gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
release_mem_region(gx1_gx_base() + 0x8300, 0x100);
}
if (info) {
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
return ret;
}
......
......@@ -444,10 +444,8 @@ static int gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_release_region(pdev, 1);
}
if (info) {
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
return ret;
}
......
......@@ -577,10 +577,8 @@ static int lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_release_region(pdev, 3);
}
if (info) {
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
}
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
return ret;
}
......
......@@ -417,8 +417,7 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset < 0 ||
var->yoffset >= info->var.yres_virtual ||
if (var->yoffset >= info->var.yres_virtual ||
var->xoffset)
return -EINVAL;
} else {
......
obj-y += core.o hw/ panel/ fb/
obj-$(CONFIG_MMP_DISP) += mmp_disp.o hw/ panel/ fb/
mmp_disp-y += core.o
if MMP_DISP
config MMP_FB
bool "fb driver for Marvell MMP Display Subsystem"
tristate "fb driver for Marvell MMP Display Subsystem"
depends on FB
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
......
......@@ -61,7 +61,7 @@ struct ocfb_dev {
/* flag indicating whether the regs are little endian accessed */
int little_endian;
/* Physical and virtual addresses of framebuffer */
phys_addr_t fb_phys;
dma_addr_t fb_phys;
void __iomem *fb_virt;
u32 pseudo_palette[PALETTE_SIZE];
};
......
menu "OMAP Display Device Drivers (new device model)"
depends on OMAP2_DSS
config DISPLAY_ENCODER_OPA362
tristate "OPA362 external analog amplifier"
help
Driver for OPA362 external analog TV amplifier controlled
through a GPIO.
config DISPLAY_ENCODER_TFP410
tristate "TFP410 DPI to DVI Encoder"
help
......
obj-$(CONFIG_DISPLAY_ENCODER_OPA362) += encoder-opa362.o
obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
......
......@@ -208,7 +208,7 @@ static int tvc_probe_pdata(struct platform_device *pdev)
ddata->in = in;
ddata->connector_type = pdata->connector_type;
ddata->invert_polarity = ddata->invert_polarity;
ddata->invert_polarity = pdata->invert_polarity;
dssdev = &ddata->dssdev;
dssdev->name = pdata->name;
......
/*
* OPA362 analog video amplifier with output/power control
*
* Copyright (C) 2014 Golden Delicious Computers
* Author: H. Nikolaus Schaller <hns@goldelico.com>
*
* based on encoder-tfp410
*
* Copyright (C) 2013 Texas Instruments
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#include <video/omapdss.h>
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
struct gpio_desc *enable_gpio;
struct omap_video_timings timings;
};
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
static int opa362_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
dev_dbg(dssdev->dev, "connect\n");
if (omapdss_device_is_connected(dssdev))
return -EBUSY;
r = in->ops.atv->connect(in, dssdev);
if (r)
return r;
dst->src = dssdev;
dssdev->dst = dst;
return 0;
}
static void opa362_disconnect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
dev_dbg(dssdev->dev, "disconnect\n");
WARN_ON(!omapdss_device_is_connected(dssdev));
if (!omapdss_device_is_connected(dssdev))
return;
WARN_ON(dst != dssdev->dst);
if (dst != dssdev->dst)
return;
dst->src = NULL;
dssdev->dst = NULL;
in->ops.atv->disconnect(in, &ddata->dssdev);
}
static int opa362_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
dev_dbg(dssdev->dev, "enable\n");
if (!omapdss_device_is_connected(dssdev))
return -ENODEV;
if (omapdss_device_is_enabled(dssdev))
return 0;
in->ops.atv->set_timings(in, &ddata->timings);
r = in->ops.atv->enable(in);
if (r)
return r;
if (ddata->enable_gpio)
gpiod_set_value_cansleep(ddata->enable_gpio, 1);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
return 0;
}
static void opa362_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
dev_dbg(dssdev->dev, "disable\n");
if (!omapdss_device_is_enabled(dssdev))
return;
if (ddata->enable_gpio)
gpiod_set_value_cansleep(ddata->enable_gpio, 0);
in->ops.atv->disable(in);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
static void opa362_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
dev_dbg(dssdev->dev, "set_timings\n");
ddata->timings = *timings;
dssdev->panel.timings = *timings;
in->ops.atv->set_timings(in, timings);
}
static void opa362_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
dev_dbg(dssdev->dev, "get_timings\n");
*timings = ddata->timings;
}
static int opa362_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
dev_dbg(dssdev->dev, "check_timings\n");
return in->ops.atv->check_timings(in, timings);
}
static void opa362_set_type(struct omap_dss_device *dssdev,
enum omap_dss_venc_type type)
{
/* we can only drive a COMPOSITE output */
WARN_ON(type != OMAP_DSS_VENC_TYPE_COMPOSITE);
}
static const struct omapdss_atv_ops opa362_atv_ops = {
.connect = opa362_connect,
.disconnect = opa362_disconnect,
.enable = opa362_enable,
.disable = opa362_disable,
.check_timings = opa362_check_timings,
.set_timings = opa362_set_timings,
.get_timings = opa362_get_timings,
.set_type = opa362_set_type,
};
static int opa362_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct panel_drv_data *ddata;
struct omap_dss_device *dssdev, *in;
struct gpio_desc *gpio;
int r;
dev_dbg(&pdev->dev, "probe\n");
if (node == NULL) {
dev_err(&pdev->dev, "Unable to find device tree\n");
return -EINVAL;
}
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
platform_set_drvdata(pdev, ddata);
gpio = devm_gpiod_get(&pdev->dev, "enable");
if (IS_ERR(gpio)) {
if (PTR_ERR(gpio) != -ENOENT)
return PTR_ERR(gpio);
gpio = NULL;
} else {
gpiod_direction_output(gpio, 0);
}
ddata->enable_gpio = gpio;
in = omapdss_of_find_source_for_first_ep(node);
if (IS_ERR(in)) {
dev_err(&pdev->dev, "failed to find video source\n");
return PTR_ERR(in);
}
ddata->in = in;
dssdev = &ddata->dssdev;
dssdev->ops.atv = &opa362_atv_ops;
dssdev->dev = &pdev->dev;
dssdev->type = OMAP_DISPLAY_TYPE_VENC;
dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
dssdev->owner = THIS_MODULE;
r = omapdss_register_output(dssdev);
if (r) {
dev_err(&pdev->dev, "Failed to register output\n");
goto err_reg;
}
return 0;
err_reg:
omap_dss_put_device(ddata->in);
return r;
}
static int __exit opa362_remove(struct platform_device *pdev)
{
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev = &ddata->dssdev;
struct omap_dss_device *in = ddata->in;
omapdss_unregister_output(&ddata->dssdev);
WARN_ON(omapdss_device_is_enabled(dssdev));
if (omapdss_device_is_enabled(dssdev))
opa362_disable(dssdev);
WARN_ON(omapdss_device_is_connected(dssdev));
if (omapdss_device_is_connected(dssdev))
opa362_disconnect(dssdev, dssdev->dst);
omap_dss_put_device(in);
return 0;
}
static const struct of_device_id opa362_of_match[] = {
{ .compatible = "omapdss,ti,opa362", },
{},
};
MODULE_DEVICE_TABLE(of, opa362_of_match);
static struct platform_driver opa362_driver = {
.probe = opa362_probe,
.remove = __exit_p(opa362_remove),
.driver = {
.name = "amplifier-opa362",
.owner = THIS_MODULE,
.of_match_table = opa362_of_match,
.suppress_bind_attrs = true,
},
};
module_platform_driver(opa362_driver);
MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
MODULE_DESCRIPTION("OPA362 analog video amplifier with output/power control");
MODULE_LICENSE("GPL v2");
......@@ -29,33 +29,10 @@ struct panel_drv_data {
int hpd_gpio;
struct omap_video_timings timings;
struct completion hpd_completion;
};
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
static irqreturn_t tpd_hpd_irq_handler(int irq, void *data)
{
struct panel_drv_data *ddata = data;
bool hpd;
hpd = gpio_get_value_cansleep(ddata->hpd_gpio);
dev_dbg(ddata->dssdev.dev, "hpd %d\n", hpd);
if (gpio_is_valid(ddata->ls_oe_gpio)) {
if (hpd)
gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
else
gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
}
complete_all(&ddata->hpd_completion);
return IRQ_HANDLED;
}
static int tpd_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
......@@ -70,23 +47,10 @@ static int tpd_connect(struct omap_dss_device *dssdev,
dst->src = dssdev;
dssdev->dst = dst;
reinit_completion(&ddata->hpd_completion);
gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
/* DC-DC converter needs at max 300us to get to 90% of 5V */
udelay(300);
/*
* If there's a cable connected, wait for the hpd irq to trigger,
* which turns on the level shifters.
*/
if (gpio_get_value_cansleep(ddata->hpd_gpio)) {
unsigned long to;
to = wait_for_completion_timeout(&ddata->hpd_completion,
msecs_to_jiffies(250));
WARN_ON_ONCE(to == 0);
}
return 0;
}
......@@ -179,11 +143,20 @@ static int tpd_read_edid(struct omap_dss_device *dssdev,
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
if (!gpio_get_value_cansleep(ddata->hpd_gpio))
return -ENODEV;
return in->ops.hdmi->read_edid(in, edid, len);
if (gpio_is_valid(ddata->ls_oe_gpio))
gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
r = in->ops.hdmi->read_edid(in, edid, len);
if (gpio_is_valid(ddata->ls_oe_gpio))
gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
return r;
}
static bool tpd_detect(struct omap_dss_device *dssdev)
......@@ -309,8 +282,6 @@ static int tpd_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ddata);
init_completion(&ddata->hpd_completion);
if (dev_get_platdata(&pdev->dev)) {
r = tpd_probe_pdata(pdev);
if (r)
......@@ -340,13 +311,6 @@ static int tpd_probe(struct platform_device *pdev)
if (r)
goto err_gpio;
r = devm_request_threaded_irq(&pdev->dev, gpio_to_irq(ddata->hpd_gpio),
NULL, tpd_hpd_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_ONESHOT, "hpd", ddata);
if (r)
goto err_irq;
dssdev = &ddata->dssdev;
dssdev->ops.hdmi = &tpd_hdmi_ops;
dssdev->dev = &pdev->dev;
......@@ -365,7 +329,6 @@ static int tpd_probe(struct platform_device *pdev)
return 0;
err_reg:
err_irq:
err_gpio:
omap_dss_put_device(ddata->in);
return r;
......
......@@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
# Core DSS files
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
output.o dss-of.o pll.o
output.o dss-of.o pll.o video-pll.o
# DSS compat layer files
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
dispc-compat.o display-sysfs.o
......
......@@ -36,6 +36,9 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sizes.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <video/omapdss.h>
......@@ -117,6 +120,9 @@ static struct {
const struct dispc_features *feat;
bool is_enabled;
struct regmap *syscon_pol;
u32 syscon_pol_offset;
} dispc;
enum omap_color_component {
......@@ -2958,6 +2964,25 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
FLD_VAL(vsync_level, 12, 12);
dispc_write_reg(DISPC_POL_FREQ(channel), l);
if (dispc.syscon_pol) {
const int shifts[] = {
[OMAP_DSS_CHANNEL_LCD] = 0,
[OMAP_DSS_CHANNEL_LCD2] = 1,
[OMAP_DSS_CHANNEL_LCD3] = 2,
};
u32 mask, val;
mask = (1 << 0) | (1 << 3) | (1 << 6);
val = (rf << 0) | (ipc << 3) | (onoff << 6);
mask <<= 16 + shifts[channel];
val <<= 16 + shifts[channel];
regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset,
mask, val);
}
}
/* change name to mode? */
......@@ -3037,10 +3062,16 @@ unsigned long dispc_fclk_rate(void)
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi0");
if (!pll)
pll = dss_pll_find("video0");
r = pll->cinfo.clkout[0];
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi1");
if (!pll)
pll = dss_pll_find("video1");
r = pll->cinfo.clkout[0];
break;
default:
......@@ -3069,10 +3100,16 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi0");
if (!pll)
pll = dss_pll_find("video0");
r = pll->cinfo.clkout[0];
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi1");
if (!pll)
pll = dss_pll_find("video1");
r = pll->cinfo.clkout[0];
break;
default:
......@@ -3668,6 +3705,7 @@ static int __init dispc_init_features(struct platform_device *pdev)
break;
case OMAPDSS_VER_OMAP5:
case OMAPDSS_VER_DRA7xx:
src = &omap54xx_dispc_feats;
break;
......@@ -3728,6 +3766,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
u32 rev;
int r = 0;
struct resource *dispc_mem;
struct device_node *np = pdev->dev.of_node;
dispc.pdev = pdev;
......@@ -3754,6 +3793,20 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
return -ENODEV;
}
if (np && of_property_read_bool(np, "syscon-pol")) {
dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
if (IS_ERR(dispc.syscon_pol)) {
dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
return PTR_ERR(dispc.syscon_pol);
}
if (of_property_read_u32_index(np, "syscon-pol", 1,
&dispc.syscon_pol_offset)) {
dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
return -EINVAL;
}
}
pm_runtime_enable(&pdev->dev);
r = dispc_runtime_get();
......@@ -3832,6 +3885,7 @@ static const struct of_device_id dispc_of_match[] = {
{ .compatible = "ti,omap3-dispc", },
{ .compatible = "ti,omap4-dispc", },
{ .compatible = "ti,omap5-dispc", },
{ .compatible = "ti,dra7-dispc", },
{},
};
......
......@@ -106,6 +106,17 @@ static struct dss_pll *dpi_get_pll(enum omap_channel channel)
return NULL;
}
case OMAPDSS_VER_DRA7xx:
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
case OMAP_DSS_CHANNEL_LCD2:
return dss_pll_find("video0");
case OMAP_DSS_CHANNEL_LCD3:
return dss_pll_find("video1");
default:
return NULL;
}
default:
return NULL;
}
......@@ -590,6 +601,10 @@ static void dpi_init_pll(struct dpi_data *dpi)
if (!pll)
return;
/* On DRA7 we need to set a mux to use the PLL */
if (omapdss_get_version() == OMAPDSS_VER_DRA7xx)
dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel);
if (dpi_verify_dsi_pll(pll)) {
DSSWARN("DSI PLL not operational\n");
return;
......@@ -615,6 +630,17 @@ static enum omap_channel dpi_get_channel(int port_num)
case OMAPDSS_VER_AM43xx:
return OMAP_DSS_CHANNEL_LCD;
case OMAPDSS_VER_DRA7xx:
switch (port_num) {
case 2:
return OMAP_DSS_CHANNEL_LCD3;
case 1:
return OMAP_DSS_CHANNEL_LCD2;
case 0:
default:
return OMAP_DSS_CHANNEL_LCD;
}
case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
......
......@@ -5238,6 +5238,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev)
}
pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1";
pll->id = dsi->module_id == 0 ? DSS_PLL_DSI1 : DSS_PLL_DSI2;
pll->clkin = clk;
pll->base = dsi->pll_base;
......
......@@ -34,7 +34,10 @@
#include <linux/pm_runtime.h>
#include <linux/gfp.h>
#include <linux/sizes.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
......@@ -63,14 +66,11 @@ struct dss_reg {
#define REG_FLD_MOD(idx, val, start, end) \
dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
static int dss_runtime_get(void);
static void dss_runtime_put(void);
struct dss_features {
u8 fck_div_max;
u8 dss_fck_multiplier;
const char *parent_clk_name;
enum omap_display_type *ports;
const enum omap_display_type *ports;
int num_ports;
int (*dpi_select_source)(int port, enum omap_channel channel);
};
......@@ -78,6 +78,8 @@ struct dss_features {
static struct {
struct platform_device *pdev;
void __iomem *base;
struct regmap *syscon_pll_ctrl;
u32 syscon_pll_ctrl_offset;
struct clk *parent_clk;
struct clk *dss_clk;
......@@ -95,6 +97,9 @@ static struct {
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
const struct dss_features *feat;
struct dss_pll *video1_pll;
struct dss_pll *video2_pll;
} dss;
static const char * const dss_generic_clk_source_names[] = {
......@@ -158,6 +163,99 @@ static void dss_restore_context(void)
#undef SR
#undef RR
void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable)
{
unsigned shift;
unsigned val;
if (!dss.syscon_pll_ctrl)
return;
val = !enable;
switch (pll_id) {
case DSS_PLL_VIDEO1:
shift = 0;
break;
case DSS_PLL_VIDEO2:
shift = 1;
break;
case DSS_PLL_HDMI:
shift = 2;
break;
default:
DSSERR("illegal DSS PLL ID %d\n", pll_id);
return;
}
regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
1 << shift, val << shift);
}
void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
enum omap_channel channel)
{
unsigned shift, val;
if (!dss.syscon_pll_ctrl)
return;
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
shift = 3;
switch (pll_id) {
case DSS_PLL_VIDEO1:
val = 0; break;
case DSS_PLL_HDMI:
val = 1; break;
default:
DSSERR("error in PLL mux config for LCD\n");
return;
}
break;
case OMAP_DSS_CHANNEL_LCD2:
shift = 5;
switch (pll_id) {
case DSS_PLL_VIDEO1:
val = 0; break;
case DSS_PLL_VIDEO2:
val = 1; break;
case DSS_PLL_HDMI:
val = 2; break;
default:
DSSERR("error in PLL mux config for LCD2\n");
return;
}
break;
case OMAP_DSS_CHANNEL_LCD3:
shift = 7;
switch (pll_id) {
case DSS_PLL_VIDEO1:
val = 1; break;
case DSS_PLL_VIDEO2:
val = 0; break;
case DSS_PLL_HDMI:
val = 2; break;
default:
DSSERR("error in PLL mux config for LCD3\n");
return;
}
break;
default:
DSSERR("error in PLL mux config\n");
return;
}
regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
0x3 << shift, val << shift);
}
void dss_sdi_init(int datapairs)
{
u32 l;
......@@ -605,6 +703,26 @@ static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
return 0;
}
static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel)
{
switch (port) {
case 0:
return dss_dpi_select_source_omap5(port, channel);
case 1:
if (channel != OMAP_DSS_CHANNEL_LCD2)
return -EINVAL;
break;
case 2:
if (channel != OMAP_DSS_CHANNEL_LCD3)
return -EINVAL;
break;
default:
return -EINVAL;
}
return 0;
}
int dss_dpi_select_source(int port, enum omap_channel channel)
{
return dss.feat->dpi_select_source(port, channel);
......@@ -643,7 +761,7 @@ static void dss_put_clocks(void)
clk_put(dss.parent_clk);
}
static int dss_runtime_get(void)
int dss_runtime_get(void)
{
int r;
......@@ -654,7 +772,7 @@ static int dss_runtime_get(void)
return r < 0 ? r : 0;
}
static void dss_runtime_put(void)
void dss_runtime_put(void)
{
int r;
......@@ -677,15 +795,21 @@ void dss_debug_dump_clocks(struct seq_file *s)
#endif
static enum omap_display_type omap2plus_ports[] = {
static const enum omap_display_type omap2plus_ports[] = {
OMAP_DISPLAY_TYPE_DPI,
};
static enum omap_display_type omap34xx_ports[] = {
static const enum omap_display_type omap34xx_ports[] = {
OMAP_DISPLAY_TYPE_DPI,
OMAP_DISPLAY_TYPE_SDI,
};
static const enum omap_display_type dra7xx_ports[] = {
OMAP_DISPLAY_TYPE_DPI,
OMAP_DISPLAY_TYPE_DPI,
OMAP_DISPLAY_TYPE_DPI,
};
static const struct dss_features omap24xx_dss_feats __initconst = {
/*
* fck div max is really 16, but the divider range has gaps. The range
......@@ -744,6 +868,15 @@ static const struct dss_features am43xx_dss_feats __initconst = {
.num_ports = ARRAY_SIZE(omap2plus_ports),
};
static const struct dss_features dra7xx_dss_feats __initconst = {
.fck_div_max = 64,
.dss_fck_multiplier = 1,
.parent_clk_name = "dpll_per_x2_ck",
.dpi_select_source = &dss_dpi_select_source_dra7xx,
.ports = dra7xx_ports,
.num_ports = ARRAY_SIZE(dra7xx_ports),
};
static int __init dss_init_features(struct platform_device *pdev)
{
const struct dss_features *src;
......@@ -784,6 +917,10 @@ static int __init dss_init_features(struct platform_device *pdev)
src = &am43xx_dss_feats;
break;
case OMAPDSS_VER_DRA7xx:
src = &dra7xx_dss_feats;
break;
default:
return -ENODEV;
}
......@@ -884,8 +1021,10 @@ static void __exit dss_uninit_ports(struct platform_device *pdev)
static int __init omap_dsshw_probe(struct platform_device *pdev)
{
struct resource *dss_mem;
struct device_node *np = pdev->dev.of_node;
u32 rev;
int r;
struct regulator *pll_regulator;
dss.pdev = pdev;
......@@ -940,6 +1079,57 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
dss_init_ports(pdev);
if (np && of_property_read_bool(np, "syscon-pll-ctrl")) {
dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np,
"syscon-pll-ctrl");
if (IS_ERR(dss.syscon_pll_ctrl)) {
dev_err(&pdev->dev,
"failed to get syscon-pll-ctrl regmap\n");
return PTR_ERR(dss.syscon_pll_ctrl);
}
if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1,
&dss.syscon_pll_ctrl_offset)) {
dev_err(&pdev->dev,
"failed to get syscon-pll-ctrl offset\n");
return -EINVAL;
}
}
pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
if (IS_ERR(pll_regulator)) {
r = PTR_ERR(pll_regulator);
switch (r) {
case -ENOENT:
pll_regulator = NULL;
break;
case -EPROBE_DEFER:
return -EPROBE_DEFER;
default:
DSSERR("can't get DPLL VDDA regulator\n");
return r;
}
}
if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator);
if (IS_ERR(dss.video1_pll)) {
r = PTR_ERR(dss.video1_pll);
goto err_pll_init;
}
}
if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator);
if (IS_ERR(dss.video2_pll)) {
r = PTR_ERR(dss.video2_pll);
goto err_pll_init;
}
}
rev = dss_read_reg(DSS_REVISION);
printk(KERN_INFO "OMAP DSS rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
......@@ -950,6 +1140,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
return 0;
err_pll_init:
if (dss.video1_pll)
dss_video_pll_uninit(dss.video1_pll);
if (dss.video2_pll)
dss_video_pll_uninit(dss.video2_pll);
err_runtime_get:
pm_runtime_disable(&pdev->dev);
err_setup_clocks:
......@@ -959,6 +1155,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
static int __exit omap_dsshw_remove(struct platform_device *pdev)
{
if (dss.video1_pll)
dss_video_pll_uninit(dss.video1_pll);
if (dss.video2_pll)
dss_video_pll_uninit(dss.video2_pll);
dss_uninit_ports(pdev);
pm_runtime_disable(&pdev->dev);
......@@ -1003,6 +1205,7 @@ static const struct of_device_id dss_of_match[] = {
{ .compatible = "ti,omap3-dss", },
{ .compatible = "ti,omap4-dss", },
{ .compatible = "ti,omap5-dss", },
{ .compatible = "ti,dra7-dss", },
{},
};
......
......@@ -100,6 +100,14 @@ enum dss_writeback_channel {
DSS_WB_LCD3_MGR = 7,
};
enum dss_pll_id {
DSS_PLL_DSI1,
DSS_PLL_DSI2,
DSS_PLL_HDMI,
DSS_PLL_VIDEO1,
DSS_PLL_VIDEO2,
};
struct dss_pll;
#define DSS_PLL_MAX_HSDIVS 4
......@@ -150,6 +158,7 @@ struct dss_pll_hw {
struct dss_pll {
const char *name;
enum dss_pll_id id;
struct clk *clkin;
struct regulator *regulator;
......@@ -250,6 +259,9 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void);
int dss_runtime_get(void);
void dss_runtime_put(void);
unsigned long dss_get_dispc_clk_rate(void);
int dss_dpi_select_source(int port, enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
......@@ -257,6 +269,11 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
void dss_dump_clocks(struct seq_file *s);
/* DSS VIDEO PLL */
struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
struct regulator *regulator);
void dss_video_pll_uninit(struct dss_pll *pll);
/* dss-of */
struct device_node *dss_of_port_get_parent_device(struct device_node *port);
u32 dss_of_port_get_port_number(struct device_node *port);
......@@ -265,6 +282,10 @@ u32 dss_of_port_get_port_number(struct device_node *port);
void dss_debug_dump_clocks(struct seq_file *s);
#endif
void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable);
void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
enum omap_channel channel);
void dss_sdi_init(int datapairs);
int dss_sdi_enable(void);
void dss_sdi_disable(void);
......@@ -446,5 +467,6 @@ int dss_pll_write_config_type_a(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
int dss_pll_write_config_type_b(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
int dss_pll_wait_reset_done(struct dss_pll *pll);
#endif
......@@ -223,7 +223,7 @@ static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI,
OMAP_DSS_OUTPUT_HDMI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
......@@ -943,6 +943,7 @@ void dss_features_init(enum omapdss_version version)
break;
case OMAPDSS_VER_OMAP5:
case OMAPDSS_VER_DRA7xx:
omap_current_dss_features = &omap5_dss_features;
break;
......
......@@ -787,6 +787,7 @@ static const struct dev_pm_ops hdmi_pm_ops = {
static const struct of_device_id hdmi_of_match[] = {
{ .compatible = "ti,omap5-hdmi", },
{ .compatible = "ti,dra7-hdmi", },
{},
};
......
......@@ -208,6 +208,7 @@ static int hdmi_phy_init_features(struct platform_device *pdev)
break;
case OMAPDSS_VER_OMAP5:
case OMAPDSS_VER_DRA7xx:
src = &omap54xx_phy_feats;
break;
......
......@@ -104,6 +104,8 @@ static int hdmi_pll_enable(struct dss_pll *dsspll)
struct hdmi_wp_data *wp = pll->wp;
u16 r = 0;
dss_ctrl_pll_enable(DSS_PLL_HDMI, true);
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
if (r)
return r;
......@@ -117,6 +119,8 @@ static void hdmi_pll_disable(struct dss_pll *dsspll)
struct hdmi_wp_data *wp = pll->wp;
hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
dss_ctrl_pll_enable(DSS_PLL_HDMI, false);
}
static const struct dss_pll_ops dsi_pll_ops = {
......@@ -185,6 +189,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data
}
pll->name = "hdmi";
pll->id = DSS_PLL_HDMI;
pll->base = hpll->base;
pll->clkin = clk;
......@@ -196,6 +201,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data
break;
case OMAPDSS_VER_OMAP5:
case OMAPDSS_VER_DRA7xx:
pll->hw = &dss_omap5_hdmi_pll_hw;
break;
......
......@@ -186,6 +186,7 @@ static const struct of_device_id omapdss_of_match[] __initconst = {
{ .compatible = "ti,omap3-dss", },
{ .compatible = "ti,omap4-dss", },
{ .compatible = "ti,omap5-dss", },
{ .compatible = "ti,dra7-dss", },
{},
};
......
......@@ -222,6 +222,16 @@ static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
return !value;
}
int dss_pll_wait_reset_done(struct dss_pll *pll)
{
void __iomem *base = pll->base;
if (wait_for_bit_change(base + PLL_STATUS, 0, 1) != 1)
return -ETIMEDOUT;
else
return 0;
}
static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
{
int t = 100;
......
/*
* Copyright (C) 2014 Texas Instruments Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <video/omapdss.h>
#include "dss.h"
#include "dss_features.h"
struct dss_video_pll {
struct dss_pll pll;
struct device *dev;
void __iomem *clkctrl_base;
};
#define REG_MOD(reg, val, start, end) \
writel_relaxed(FLD_MOD(readl_relaxed(reg), val, start, end), reg)
static void dss_dpll_enable_scp_clk(struct dss_video_pll *vpll)
{
REG_MOD(vpll->clkctrl_base, 1, 14, 14); /* CIO_CLK_ICG */
}
static void dss_dpll_disable_scp_clk(struct dss_video_pll *vpll)
{
REG_MOD(vpll->clkctrl_base, 0, 14, 14); /* CIO_CLK_ICG */
}
static void dss_dpll_power_enable(struct dss_video_pll *vpll)
{
REG_MOD(vpll->clkctrl_base, 2, 31, 30); /* PLL_POWER_ON_ALL */
/*
* DRA7x PLL CTRL's PLL_PWR_STATUS seems to always return 0,
* so we have to use fixed delay here.
*/
msleep(1);
}
static void dss_dpll_power_disable(struct dss_video_pll *vpll)
{
REG_MOD(vpll->clkctrl_base, 0, 31, 30); /* PLL_POWER_OFF */
}
static int dss_video_pll_enable(struct dss_pll *pll)
{
struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
int r;
r = dss_runtime_get();
if (r)
return r;
dss_ctrl_pll_enable(pll->id, true);
dss_dpll_enable_scp_clk(vpll);
r = dss_pll_wait_reset_done(pll);
if (r)
goto err_reset;
dss_dpll_power_enable(vpll);
return 0;
err_reset:
dss_dpll_disable_scp_clk(vpll);
dss_ctrl_pll_enable(pll->id, false);
dss_runtime_put();
return r;
}
static void dss_video_pll_disable(struct dss_pll *pll)
{
struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
dss_dpll_power_disable(vpll);
dss_dpll_disable_scp_clk(vpll);
dss_ctrl_pll_enable(pll->id, false);
dss_runtime_put();
}
static const struct dss_pll_ops dss_pll_ops = {
.enable = dss_video_pll_enable,
.disable = dss_video_pll_disable,
.set_config = dss_pll_write_config_type_a,
};
static const struct dss_pll_hw dss_dra7_video_pll_hw = {
.n_max = (1 << 8) - 1,
.m_max = (1 << 12) - 1,
.mX_max = (1 << 5) - 1,
.fint_min = 500000,
.fint_max = 2500000,
.clkdco_max = 1800000000,
.n_msb = 8,
.n_lsb = 1,
.m_msb = 20,
.m_lsb = 9,
.mX_msb[0] = 25,
.mX_lsb[0] = 21,
.mX_msb[1] = 30,
.mX_lsb[1] = 26,
.has_refsel = true,
};
struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
struct regulator *regulator)
{
const char * const reg_name[] = { "pll1", "pll2" };
const char * const clkctrl_name[] = { "pll1_clkctrl", "pll2_clkctrl" };
const char * const clkin_name[] = { "video1_clk", "video2_clk" };
struct resource *res;
struct dss_video_pll *vpll;
void __iomem *pll_base, *clkctrl_base;
struct clk *clk;
struct dss_pll *pll;
int r;
/* PLL CONTROL */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, reg_name[id]);
if (!res) {
dev_err(&pdev->dev,
"missing platform resource data for pll%d\n", id);
return ERR_PTR(-ENODEV);
}
pll_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pll_base)) {
dev_err(&pdev->dev, "failed to ioremap pll%d reg_name\n", id);
return ERR_CAST(pll_base);
}
/* CLOCK CONTROL */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
clkctrl_name[id]);
if (!res) {
dev_err(&pdev->dev,
"missing platform resource data for pll%d\n", id);
return ERR_PTR(-ENODEV);
}
clkctrl_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(clkctrl_base)) {
dev_err(&pdev->dev, "failed to ioremap pll%d clkctrl\n", id);
return ERR_CAST(clkctrl_base);
}
/* CLKIN */
clk = devm_clk_get(&pdev->dev, clkin_name[id]);
if (IS_ERR(clk)) {
DSSERR("can't get video pll clkin\n");
return ERR_CAST(clk);
}
vpll = devm_kzalloc(&pdev->dev, sizeof(*vpll), GFP_KERNEL);
if (!vpll)
return ERR_PTR(-ENOMEM);
vpll->dev = &pdev->dev;
vpll->clkctrl_base = clkctrl_base;
pll = &vpll->pll;
pll->name = id == 0 ? "video0" : "video1";
pll->id = id == 0 ? DSS_PLL_VIDEO1 : DSS_PLL_VIDEO2;
pll->clkin = clk;
pll->regulator = regulator;
pll->base = pll_base;
pll->hw = &dss_dra7_video_pll_hw;
pll->ops = &dss_pll_ops;
r = dss_pll_register(pll);
if (r)
return ERR_PTR(r);
return pll;
}
void dss_video_pll_uninit(struct dss_pll *pll)
{
dss_pll_unregister(pll);
}
......@@ -137,8 +137,11 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
goto undo;
}
if (ovl->manager)
ovl->manager->apply(ovl->manager);
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
if (r)
goto undo;
}
if (pi->enabled) {
r = ovl->enable(ovl);
......
......@@ -351,32 +351,26 @@ static inline void VGAwSEQ(u8 index, u8 val, struct savagefb_par *par)
static inline void VGAenablePalette(struct savagefb_par *par)
{
u8 tmp;
tmp = vga_in8(0x3da, par);
vga_in8(0x3da, par);
vga_out8(0x3c0, 0x00, par);
par->paletteEnabled = 1;
}
static inline void VGAdisablePalette(struct savagefb_par *par)
{
u8 tmp;
tmp = vga_in8(0x3da, par);
vga_in8(0x3da, par);
vga_out8(0x3c0, 0x20, par);
par->paletteEnabled = 0;
}
static inline void VGAwATTR(u8 index, u8 value, struct savagefb_par *par)
{
u8 tmp;
if (par->paletteEnabled)
index &= ~0x20;
else
index |= 0x20;
tmp = vga_in8(0x3da, par);
vga_in8(0x3da, par);
vga_out8(0x3c0, index, par);
vga_out8 (0x3c0, value, par);
}
......
......@@ -122,23 +122,6 @@ static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
return ret;
}
static inline int ssd1307fb_write_data(struct i2c_client *client, u8 data)
{
struct ssd1307fb_array *array;
int ret;
array = ssd1307fb_alloc_array(1, SSD1307FB_DATA);
if (!array)
return -ENOMEM;
array->data[0] = data;
ret = ssd1307fb_write_array(client, array, 1);
kfree(array);
return ret;
}
static void ssd1307fb_update_display(struct ssd1307fb_par *par)
{
struct ssd1307fb_array *array;
......@@ -320,7 +303,10 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
/* Set initial contrast */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
ret = ret & ssd1307fb_write_cmd(par->client, 0x7f);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, 0x7f);
if (ret < 0)
return ret;
......@@ -336,63 +322,99 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
/* Set multiplex ratio value */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO);
ret = ret & ssd1307fb_write_cmd(par->client, par->height - 1);
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, 0x20);
if (ret < 0)
return ret;
/* Set clock frequency */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ);
ret = ret & ssd1307fb_write_cmd(par->client, 0xf0);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, 0xf0);
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);
ret = ret & ssd1307fb_write_cmd(par->client, 0x22);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, 0x22);
if (ret < 0)
return ret;
/* Set COM pins configuration */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG);
ret = ret & ssd1307fb_write_cmd(par->client, 0x22);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, 0x22);
if (ret < 0)
return ret;
/* Set VCOMH */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH);
ret = ret & ssd1307fb_write_cmd(par->client, 0x49);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, 0x49);
if (ret < 0)
return ret;
/* Turn on the DC-DC Charge Pump */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
ret = ret & ssd1307fb_write_cmd(par->client, 0x14);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, 0x14);
if (ret < 0)
return ret;
/* Switch to horizontal addressing mode */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
ret = ret & ssd1307fb_write_cmd(par->client,
SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client,
SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
ret = ret & ssd1307fb_write_cmd(par->client, 0x0);
ret = ret & ssd1307fb_write_cmd(par->client, par->width - 1);
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;
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
ret = ret & ssd1307fb_write_cmd(par->client, 0x0);
ret = ret & ssd1307fb_write_cmd(par->client,
par->page_offset + (par->height / 8) - 1);
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;
......@@ -460,7 +482,7 @@ static int ssd1307fb_probe(struct i2c_client *client,
par->width = 96;
if (of_property_read_u32(node, "solomon,height", &par->height))
par->width = 16;
par->height = 16;
if (of_property_read_u32(node, "solomon,page-offset", &par->page_offset))
par->page_offset = 1;
......
......@@ -113,10 +113,8 @@ static int vt8500lcd_set_par(struct fb_info *info)
}
for (i = 0; i < 8; i++) {
if (bpp_values[i] == info->var.bits_per_pixel) {
if (bpp_values[i] == info->var.bits_per_pixel)
reg_bpp = i;
continue;
}
}
control0 = readl(fbi->regbase) & ~0xf;
......
......@@ -2,7 +2,7 @@
* linux/drivers/video/vgastate.c -- VGA state save/restore
*
* Copyright 2002 James Simmons
*
*
* Copyright history from vga16fb.c:
* Copyright 1999 Ben Pfaff and Petr Vandrovec
* Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
......@@ -10,7 +10,7 @@
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
* archive for more details.
* archive for more details.
*
*/
#include <linux/module.h>
......@@ -29,16 +29,16 @@ struct regstate {
__u8 *gfx;
__u8 *seq;
__u8 misc;
};
};
static inline unsigned char vga_rcrtcs(void __iomem *regbase, unsigned short iobase,
static inline unsigned char vga_rcrtcs(void __iomem *regbase, unsigned short iobase,
unsigned char reg)
{
vga_w(regbase, iobase + 0x4, reg);
return vga_r(regbase, iobase + 0x5);
}
static inline void vga_wcrtcs(void __iomem *regbase, unsigned short iobase,
static inline void vga_wcrtcs(void __iomem *regbase, unsigned short iobase,
unsigned char reg, unsigned char val)
{
vga_w(regbase, iobase + 0x4, reg);
......@@ -71,7 +71,7 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC);
seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
/* blank screen */
seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
......@@ -85,7 +85,7 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 4 * 8192; i++)
for (i = 0; i < 4 * 8192; i++)
saved->vga_font0[i] = vga_r(fbbase, i);
}
......@@ -96,10 +96,10 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < state->memsize; i++)
for (i = 0; i < state->memsize; i++)
saved->vga_font1[i] = vga_r(fbbase, i);
}
/* save font at plane 0/1 */
if (state->flags & VGA_SAVE_TEXT) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1);
......@@ -107,7 +107,7 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 8192; i++)
for (i = 0; i < 8192; i++)
saved->vga_text[i] = vga_r(fbbase, i);
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2);
......@@ -115,8 +115,8 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 8192; i++)
saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i);
for (i = 0; i < 8192; i++)
saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i);
}
/* restore regs */
......@@ -151,7 +151,7 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
gr8 = vga_rgfx(state->vgabase, VGA_GFX_BIT_MASK);
seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
/* blank screen */
seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
......@@ -163,7 +163,7 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, 0xff);
vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, 0x00);
}
/* restore font at plane 2 */
if (state->flags & VGA_SAVE_FONT0) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4);
......@@ -171,7 +171,7 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 4 * 8192; i++)
for (i = 0; i < 4 * 8192; i++)
vga_w(fbbase, i, saved->vga_font0[i]);
}
......@@ -182,10 +182,10 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < state->memsize; i++)
for (i = 0; i < state->memsize; i++)
vga_w(fbbase, i, saved->vga_font1[i]);
}
/* restore font at plane 0/1 */
if (state->flags & VGA_SAVE_TEXT) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1);
......@@ -193,16 +193,16 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 8192; i++)
for (i = 0; i < 8192; i++)
vga_w(fbbase, i, saved->vga_text[i]);
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
for (i = 0; i < 8192; i++)
vga_w(fbbase, i, saved->vga_text[8192+i]);
for (i = 0; i < 8192; i++)
vga_w(fbbase, i, saved->vga_text[8192+i]);
}
/* unblank screen */
......@@ -222,7 +222,7 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4);
}
static void save_vga_mode(struct vgastate *state)
{
struct regstate *saved = (struct regstate *) state->vidstate;
......@@ -235,10 +235,10 @@ static void save_vga_mode(struct vgastate *state)
else
iobase = 0x3b0;
for (i = 0; i < state->num_crtc; i++)
for (i = 0; i < state->num_crtc; i++)
saved->crtc[i] = vga_rcrtcs(state->vgabase, iobase, i);
vga_r(state->vgabase, iobase + 0xa);
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x00);
for (i = 0; i < state->num_attr; i++) {
vga_r(state->vgabase, iobase + 0xa);
......@@ -247,10 +247,10 @@ static void save_vga_mode(struct vgastate *state)
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x20);
for (i = 0; i < state->num_gfx; i++)
for (i = 0; i < state->num_gfx; i++)
saved->gfx[i] = vga_rgfx(state->vgabase, i);
for (i = 0; i < state->num_seq; i++)
for (i = 0; i < state->num_seq; i++)
saved->seq[i] = vga_rseq(state->vgabase, i);
}
......@@ -268,26 +268,26 @@ static void restore_vga_mode(struct vgastate *state)
iobase = 0x3b0;
/* turn off display */
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
saved->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
/* disable sequencer */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
/* enable palette addressing */
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x00);
for (i = 2; i < state->num_seq; i++)
for (i = 2; i < state->num_seq; i++)
vga_wseq(state->vgabase, i, saved->seq[i]);
/* unprotect vga regs */
vga_wcrtcs(state->vgabase, iobase, 17, saved->crtc[17] & ~0x80);
for (i = 0; i < state->num_crtc; i++)
for (i = 0; i < state->num_crtc; i++)
vga_wcrtcs(state->vgabase, iobase, i, saved->crtc[i]);
for (i = 0; i < state->num_gfx; i++)
for (i = 0; i < state->num_gfx; i++)
vga_wgfx(state->vgabase, i, saved->gfx[i]);
for (i = 0; i < state->num_attr; i++) {
......@@ -298,7 +298,7 @@ static void restore_vga_mode(struct vgastate *state)
/* reenable sequencer */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
/* turn display on */
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
saved->seq[VGA_SEQ_CLOCK_MODE] & ~(1 << 5));
/* disable video/palette source */
......@@ -312,7 +312,7 @@ static void save_vga_cmap(struct vgastate *state)
int i;
vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
/* assumes DAC is readable and writable */
vga_w(state->vgabase, VGA_PEL_IR, 0x00);
for (i = 0; i < 768; i++)
......@@ -346,7 +346,7 @@ static void vga_cleanup(struct vgastate *state)
state->vidstate = NULL;
}
}
int save_vga(struct vgastate *state)
{
struct regstate *saved;
......@@ -357,7 +357,7 @@ int save_vga(struct vgastate *state)
return 1;
state->vidstate = (void *)saved;
if (state->flags & VGA_SAVE_CMAP) {
saved->vga_cmap = vmalloc(768);
if (!saved->vga_cmap) {
......@@ -403,7 +403,7 @@ int save_vga(struct vgastate *state)
}
if (!state->memsize)
state->memsize = 8 * 8192;
if (!state->membase)
state->membase = 0xA0000;
......@@ -414,7 +414,7 @@ int save_vga(struct vgastate *state)
return 1;
}
/*
/*
* save only first 32K used by vgacon
*/
if (state->flags & VGA_SAVE_FONT0) {
......@@ -425,7 +425,7 @@ int save_vga(struct vgastate *state)
return 1;
}
}
/*
/*
* largely unused, but if required by the caller
* we'll just save everything.
*/
......@@ -448,7 +448,7 @@ int save_vga(struct vgastate *state)
return 1;
}
}
save_vga_text(state, fbbase);
iounmap(fbbase);
}
......
......@@ -726,7 +726,9 @@ extern int fb_videomode_from_videomode(const struct videomode *vm,
struct fb_videomode *fbmode);
/* drivers/video/modedb.c */
#define VESA_MODEDB_SIZE 34
#define VESA_MODEDB_SIZE 43
#define DMT_SIZE 0x50
extern void fb_var_to_videomode(struct fb_videomode *mode,
const struct fb_var_screeninfo *var);
extern void fb_videomode_to_var(struct fb_var_screeninfo *var,
......@@ -777,9 +779,17 @@ struct fb_videomode {
u32 flag;
};
struct dmt_videomode {
u32 dmt_id;
u32 std_2byte_code;
u32 cvt_3byte_code;
const struct fb_videomode *mode;
};
extern const char *fb_mode_option;
extern const struct fb_videomode vesa_modes[];
extern const struct fb_videomode cea_modes[64];
extern const struct dmt_videomode dmt_modes[];
struct fb_modelist {
struct list_head list;
......
......@@ -314,6 +314,7 @@ enum omapdss_version {
OMAPDSS_VER_OMAP4, /* All other OMAP4s */
OMAPDSS_VER_OMAP5,
OMAPDSS_VER_AM43xx,
OMAPDSS_VER_DRA7xx,
};
/* Board specific data */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment