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 ...@@ -77,18 +77,22 @@ config DUMMY_CONSOLE
config DUMMY_CONSOLE_COLUMNS config DUMMY_CONSOLE_COLUMNS
int "Initial number of console screen columns" int "Initial number of console screen columns"
depends on PARISC && DUMMY_CONSOLE depends on DUMMY_CONSOLE && !ARM
default "160" default 160 if PARISC
default 80
help 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. Select 80 if you use a 640x480 resolution by default.
config DUMMY_CONSOLE_ROWS config DUMMY_CONSOLE_ROWS
int "Initial number of console screen rows" int "Initial number of console screen rows"
depends on PARISC && DUMMY_CONSOLE depends on DUMMY_CONSOLE && !ARM
default "64" default 64 if PARISC
default 25
help 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. Select 25 if you use a 640x480 resolution by default.
config FRAMEBUFFER_CONSOLE config FRAMEBUFFER_CONSOLE
......
...@@ -20,13 +20,10 @@ ...@@ -20,13 +20,10 @@
#if defined(__arm__) #if defined(__arm__)
#define DUMMY_COLUMNS screen_info.orig_video_cols #define DUMMY_COLUMNS screen_info.orig_video_cols
#define DUMMY_ROWS screen_info.orig_video_lines #define DUMMY_ROWS screen_info.orig_video_lines
#elif defined(__hppa__) #else
/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */ /* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */
#define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS #define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS
#define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS #define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS
#else
#define DUMMY_COLUMNS 80
#define DUMMY_ROWS 25
#endif #endif
static const char *dummycon_startup(void) static const char *dummycon_startup(void)
......
...@@ -146,9 +146,6 @@ static const struct consw fb_con; ...@@ -146,9 +146,6 @@ static const struct consw fb_con;
static int fbcon_set_origin(struct vc_data *); static int fbcon_set_origin(struct vc_data *);
#define CURSOR_DRAW_DELAY (1)
static int vbl_cursor_cnt;
static int fbcon_cursor_noblink; static int fbcon_cursor_noblink;
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
...@@ -1329,7 +1326,6 @@ static void fbcon_cursor(struct vc_data *vc, int mode) ...@@ -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), ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
get_color(vc, info, c, 0)); get_color(vc, info, c, 0));
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
} }
static int scrollback_phys_max = 0; static int scrollback_phys_max = 0;
......
...@@ -1530,13 +1530,11 @@ config FB_SIS_315 ...@@ -1530,13 +1530,11 @@ config FB_SIS_315
config FB_VIA config FB_VIA
tristate "VIA UniChrome (Pro) and Chrome9 display support" 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_FILLRECT
select FB_CFB_COPYAREA select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT select FB_CFB_IMAGEBLIT
select I2C_ALGOBIT select I2C_ALGOBIT
select I2C
select GPIOLIB
help help
This is the frame buffer device driver for Graphics chips of VIA This is the frame buffer device driver for Graphics chips of VIA
UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/ UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
...@@ -2151,7 +2149,6 @@ config FB_PS3 ...@@ -2151,7 +2149,6 @@ config FB_PS3
select FB_SYS_COPYAREA select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS select FB_SYS_FOPS
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
---help--- ---help---
Include support for the virtual frame buffer in the PS3 platform. Include support for the virtual frame buffer in the PS3 platform.
......
...@@ -3948,7 +3948,7 @@ static struct notifier_block atyfb_reboot_notifier = { ...@@ -3948,7 +3948,7 @@ static struct notifier_block atyfb_reboot_notifier = {
.notifier_call = atyfb_reboot_notify, .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", .ident = "HP OmniBook 500",
.matches = { .matches = {
...@@ -3960,6 +3960,7 @@ static const struct dmi_system_id atyfb_reboot_ids[] = { ...@@ -3960,6 +3960,7 @@ static const struct dmi_system_id atyfb_reboot_ids[] = {
{ } { }
}; };
static bool registered_notifier = false;
static int __init atyfb_init(void) static int __init atyfb_init(void)
{ {
...@@ -3982,15 +3983,17 @@ static int __init atyfb_init(void) ...@@ -3982,15 +3983,17 @@ static int __init atyfb_init(void)
if (err1 && err2) if (err1 && err2)
return -ENODEV; return -ENODEV;
if (dmi_check_system(atyfb_reboot_ids)) if (dmi_check_system(atyfb_reboot_ids)) {
register_reboot_notifier(&atyfb_reboot_notifier); register_reboot_notifier(&atyfb_reboot_notifier);
registered_notifier = true;
}
return 0; return 0;
} }
static void __exit atyfb_exit(void) static void __exit atyfb_exit(void)
{ {
if (dmi_check_system(atyfb_reboot_ids)) if (registered_notifier)
unregister_reboot_notifier(&atyfb_reboot_notifier); unregister_reboot_notifier(&atyfb_reboot_notifier);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
......
...@@ -369,9 +369,9 @@ int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb) ...@@ -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_back_porch = cvt.hblank/2 + cvt.h_margin;
cvt.h_front_porch = cvt.hblank - cvt.hsync - cvt.h_back_porch + cvt.h_front_porch = cvt.hblank - cvt.hsync - cvt.h_back_porch +
2 * cvt.h_margin; 2 * cvt.h_margin;
cvt.v_back_porch = 3 + cvt.v_margin; cvt.v_front_porch = 3 + cvt.v_margin;
cvt.v_front_porch = cvt.vtotal - cvt.yres/cvt.interlace - cvt.v_back_porch = cvt.vtotal - cvt.yres/cvt.interlace -
cvt.v_back_porch - cvt.vsync; cvt.v_front_porch - cvt.vsync;
fb_cvt_print_name(&cvt); fb_cvt_print_name(&cvt);
fb_cvt_convert_to_mode(&cvt, mode); fb_cvt_convert_to_mode(&cvt, mode);
......
...@@ -496,9 +496,24 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode) ...@@ -496,9 +496,24 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
} }
static int get_std_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; int i;
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;
}
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; xres = (block[0] + 31) * 8;
if (xres <= 256) if (xres <= 256)
...@@ -524,28 +539,28 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode, ...@@ -524,28 +539,28 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
break; break;
} }
refresh = (block[1] & 0x3f) + 60; refresh = (block[1] & 0x3f) + 60;
DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
for (i = 0; i < VESA_MODEDB_SIZE; i++) {
if (vesa_modes[i].xres == xres && calc_mode_timings(xres, yres, refresh, mode);
vesa_modes[i].yres == yres &&
vesa_modes[i].refresh == refresh) {
*mode = vesa_modes[i];
mode->flag |= FB_MODE_IS_STANDARD;
return 1;
} }
/* 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;
} }
calc_mode_timings(xres, yres, refresh, mode);
return 1; return 1;
} }
static int get_dst_timing(unsigned char *block, static int get_dst_timing(unsigned char *block, struct fb_videomode *mode,
struct fb_videomode *mode, int ver, int rev) int ver, int rev, const struct fb_monspecs *specs)
{ {
int j, num = 0; int j, num = 0;
for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE) 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; return num;
} }
...@@ -601,7 +616,8 @@ static void get_detailed_timing(unsigned char *block, ...@@ -601,7 +616,8 @@ static void get_detailed_timing(unsigned char *block,
* This function builds a mode database using the contents of the EDID * This function builds a mode database using the contents of the EDID
* data * 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; struct fb_videomode *mode, *m;
unsigned char *block; unsigned char *block;
...@@ -643,12 +659,13 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) ...@@ -643,12 +659,13 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
DPRINTK(" Standard Timings\n"); DPRINTK(" Standard Timings\n");
block = edid + STD_TIMING_DESCRIPTIONS_START; block = edid + STD_TIMING_DESCRIPTIONS_START;
for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) 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; block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) 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 */ /* Yikes, EDID data is totally useless */
...@@ -707,7 +724,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) ...@@ -707,7 +724,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
int num_modes, hz, hscan, pixclock; int num_modes, hz, hscan, pixclock;
int vtotal, htotal; int vtotal, htotal;
modes = fb_create_modedb(edid, &num_modes); modes = fb_create_modedb(edid, &num_modes, specs);
if (!modes) { if (!modes) {
DPRINTK("None Available\n"); DPRINTK("None Available\n");
return 1; return 1;
...@@ -964,7 +981,7 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) ...@@ -964,7 +981,7 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
DPRINTK(" Display Characteristics:\n"); DPRINTK(" Display Characteristics:\n");
get_monspecs(edid, specs); 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 * Workaround for buggy EDIDs that sets that the first
......
...@@ -468,8 +468,119 @@ const struct fb_videomode vesa_modes[] = { ...@@ -468,8 +468,119 @@ const struct fb_videomode vesa_modes[] = {
/* 33 1920x1440-75 VESA */ /* 33 1920x1440-75 VESA */
{ NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, 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); 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 */ #endif /* CONFIG_FB_MODE_HELPERS */
/** /**
......
...@@ -25,8 +25,8 @@ ...@@ -25,8 +25,8 @@
*/ */
static void static void
bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
const unsigned long *src, int src_idx, int bits, unsigned n) const unsigned long *src, unsigned src_idx, int bits, unsigned n)
{ {
unsigned long first, last; unsigned long first, last;
int const shift = dst_idx-src_idx; int const shift = dst_idx-src_idx;
...@@ -86,15 +86,15 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, ...@@ -86,15 +86,15 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
first &= last; first &= last;
if (shift > 0) { if (shift > 0) {
/* Single source word */ /* Single source word */
*dst = comp(*src >> right, *dst, first); *dst = comp(*src << left, *dst, first);
} else if (src_idx+n <= bits) { } else if (src_idx+n <= bits) {
/* Single source word */ /* Single source word */
*dst = comp(*src << left, *dst, first); *dst = comp(*src >> right, *dst, first);
} else { } else {
/* 2 source words */ /* 2 source words */
d0 = *src++; d0 = *src++;
d1 = *src; d1 = *src;
*dst = comp(d0 << left | d1 >> right, *dst, *dst = comp(d0 >> right | d1 << left, *dst,
first); first);
} }
} else { } else {
...@@ -109,13 +109,14 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, ...@@ -109,13 +109,14 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
/* Leading bits */ /* Leading bits */
if (shift > 0) { if (shift > 0) {
/* Single source word */ /* Single source word */
*dst = comp(d0 >> right, *dst, first); *dst = comp(d0 << left, *dst, first);
dst++; dst++;
n -= bits - dst_idx; n -= bits - dst_idx;
} else { } else {
/* 2 source words */ /* 2 source words */
d1 = *src++; d1 = *src++;
*dst = comp(d0 << left | *dst >> right, *dst, first); *dst = comp(d0 >> right | d1 << left, *dst,
first);
d0 = d1; d0 = d1;
dst++; dst++;
n -= bits - dst_idx; n -= bits - dst_idx;
...@@ -126,36 +127,36 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, ...@@ -126,36 +127,36 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
n /= bits; n /= bits;
while (n >= 4) { while (n >= 4) {
d1 = *src++; d1 = *src++;
*dst++ = d0 << left | d1 >> right; *dst++ = d0 >> right | d1 << left;
d0 = d1; d0 = d1;
d1 = *src++; d1 = *src++;
*dst++ = d0 << left | d1 >> right; *dst++ = d0 >> right | d1 << left;
d0 = d1; d0 = d1;
d1 = *src++; d1 = *src++;
*dst++ = d0 << left | d1 >> right; *dst++ = d0 >> right | d1 << left;
d0 = d1; d0 = d1;
d1 = *src++; d1 = *src++;
*dst++ = d0 << left | d1 >> right; *dst++ = d0 >> right | d1 << left;
d0 = d1; d0 = d1;
n -= 4; n -= 4;
} }
while (n--) { while (n--) {
d1 = *src++; d1 = *src++;
*dst++ = d0 << left | d1 >> right; *dst++ = d0 >> right | d1 << left;
d0 = d1; d0 = d1;
} }
/* Trailing bits */ /* Trailing bits */
if (last) { if (m) {
if (m <= right) { if (m <= bits - right) {
/* Single source word */ /* Single source word */
*dst = comp(d0 << left, *dst, last); d0 >>= right;
} else { } else {
/* 2 source words */ /* 2 source words */
d1 = *src; d1 = *src;
*dst = comp(d0 << left | d1 >> right, d0 = d0 >> right | d1 << left;
*dst, last);
} }
*dst = comp(d0, *dst, last);
} }
} }
} }
...@@ -166,40 +167,35 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx, ...@@ -166,40 +167,35 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
*/ */
static void static void
bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
const unsigned long *src, int src_idx, int bits, unsigned n) const unsigned long *src, unsigned src_idx, unsigned bits,
unsigned n)
{ {
unsigned long first, last; unsigned long first, last;
int shift; int shift;
dst += (n-1)/bits; dst += (dst_idx + n - 1) / bits;
src += (n-1)/bits; src += (src_idx + n - 1) / bits;
if ((n-1) % bits) { dst_idx = (dst_idx + n - 1) % bits;
dst_idx += (n-1) % bits; src_idx = (src_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;
}
shift = dst_idx-src_idx; shift = dst_idx-src_idx;
first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx); first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits);
last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits))); last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits);
if (!shift) { if (!shift) {
/* Same alignment for source and dest */ /* Same alignment for source and dest */
if ((unsigned long)dst_idx+1 >= n) { if ((unsigned long)dst_idx+1 >= n) {
/* Single word */ /* Single word */
if (last) if (first)
first &= last; last &= first;
*dst = comp(*src, *dst, first); *dst = comp(*src, *dst, last);
} else { } else {
/* Multiple destination words */ /* Multiple destination words */
/* Leading bits */ /* Leading bits */
if (first != ~0UL) { if (first) {
*dst = comp(*src, *dst, first); *dst = comp(*src, *dst, first);
dst--; dst--;
src--; src--;
...@@ -222,29 +218,29 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, ...@@ -222,29 +218,29 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
while (n--) while (n--)
*dst-- = *src--; *dst-- = *src--;
/* Trailing bits */ /* Trailing bits */
if (last) if (last != -1UL)
*dst = comp(*src, *dst, last); *dst = comp(*src, *dst, last);
} }
} else { } else {
/* Different alignment for source and dest */ /* Different alignment for source and dest */
int const left = -shift & (bits-1); int const left = shift & (bits-1);
int const right = shift & (bits-1); int const right = -shift & (bits-1);
if ((unsigned long)dst_idx+1 >= n) { if ((unsigned long)dst_idx+1 >= n) {
/* Single destination word */ /* Single destination word */
if (last) if (first)
first &= last; last &= first;
if (shift < 0) { if (shift < 0) {
/* Single source word */ /* Single source word */
*dst = comp(*src << left, *dst, first); *dst = comp(*src >> right, *dst, last);
} else if (1+(unsigned long)src_idx >= n) { } else if (1+(unsigned long)src_idx >= n) {
/* Single source word */ /* Single source word */
*dst = comp(*src >> right, *dst, first); *dst = comp(*src << left, *dst, last);
} else { } else {
/* 2 source words */ /* 2 source words */
*dst = comp(*src >> right | *(src-1) << left, *dst = comp(*src << left | *(src-1) >> right,
*dst, first); *dst, last);
} }
} else { } else {
/* Multiple destination words */ /* Multiple destination words */
...@@ -261,14 +257,18 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, ...@@ -261,14 +257,18 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
/* Leading bits */ /* Leading bits */
if (shift < 0) { if (shift < 0) {
/* Single source word */ /* Single source word */
*dst = comp(d0 << left, *dst, first); d1 = d0;
d0 >>= right;
} else { } else {
/* 2 source words */ /* 2 source words */
d1 = *src--; d1 = *src--;
*dst = comp(d0 >> right | d1 << left, *dst, d0 = d0 << left | d1 >> right;
first);
d0 = d1;
} }
if (!first)
*dst = d0;
else
*dst = comp(d0, *dst, first);
d0 = d1;
dst--; dst--;
n -= dst_idx+1; n -= dst_idx+1;
...@@ -277,36 +277,36 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx, ...@@ -277,36 +277,36 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
n /= bits; n /= bits;
while (n >= 4) { while (n >= 4) {
d1 = *src--; d1 = *src--;
*dst-- = d0 >> right | d1 << left; *dst-- = d0 << left | d1 >> right;
d0 = d1; d0 = d1;
d1 = *src--; d1 = *src--;
*dst-- = d0 >> right | d1 << left; *dst-- = d0 << left | d1 >> right;
d0 = d1; d0 = d1;
d1 = *src--; d1 = *src--;
*dst-- = d0 >> right | d1 << left; *dst-- = d0 << left | d1 >> right;
d0 = d1; d0 = d1;
d1 = *src--; d1 = *src--;
*dst-- = d0 >> right | d1 << left; *dst-- = d0 << left | d1 >> right;
d0 = d1; d0 = d1;
n -= 4; n -= 4;
} }
while (n--) { while (n--) {
d1 = *src--; d1 = *src--;
*dst-- = d0 >> right | d1 << left; *dst-- = d0 << left | d1 >> right;
d0 = d1; d0 = d1;
} }
/* Trailing bits */ /* Trailing bits */
if (last) { if (m) {
if (m <= left) { if (m <= bits - left) {
/* Single source word */ /* Single source word */
*dst = comp(d0 >> right, *dst, last); d0 <<= left;
} else { } else {
/* 2 source words */ /* 2 source words */
d1 = *src; d1 = *src;
*dst = comp(d0 >> right | d1 << left, d0 = d0 << left | d1 >> right;
*dst, last);
} }
*dst = comp(d0, *dst, last);
} }
} }
} }
...@@ -317,9 +317,9 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) ...@@ -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 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
u32 height = area->height, width = area->width; u32 height = area->height, width = area->width;
unsigned long const bits_per_line = p->fix.line_length*8u; 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 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) if (p->state != FBINFO_STATE_RUNNING)
return; return;
...@@ -334,8 +334,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area) ...@@ -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 /* split the base of the framebuffer into a long-aligned address and
the index of the first bit */ the index of the first bit */
dst = src = (unsigned long *)((unsigned long)p->screen_base & base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
~(bytes-1));
dst_idx = src_idx = 8*((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 */ /* add offset of source and target area */
dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; 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) ...@@ -348,20 +347,14 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
while (height--) { while (height--) {
dst_idx -= bits_per_line; dst_idx -= bits_per_line;
src_idx -= bits_per_line; src_idx -= bits_per_line;
dst += dst_idx >> (ffs(bits) - 1); bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
dst_idx &= (bytes - 1); base + (src_idx / bits), src_idx % bits, bits,
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
width*p->var.bits_per_pixel); width*p->var.bits_per_pixel);
} }
} else { } else {
while (height--) { while (height--) {
dst += dst_idx >> (ffs(bits) - 1); bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
dst_idx &= (bytes - 1); base + (src_idx / bits), src_idx % bits, bits,
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
bitcpy(p, dst, dst_idx, src, src_idx, bits,
width*p->var.bits_per_pixel); width*p->var.bits_per_pixel);
dst_idx += bits_per_line; dst_idx += bits_per_line;
src_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) ...@@ -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); release_mem_region(gx1_gx_base() + 0x8300, 0x100);
} }
if (info) {
fb_dealloc_cmap(&info->cmap); fb_dealloc_cmap(&info->cmap);
framebuffer_release(info); framebuffer_release(info);
}
return ret; return ret;
} }
......
...@@ -444,10 +444,8 @@ static int gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -444,10 +444,8 @@ static int gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_release_region(pdev, 1); pci_release_region(pdev, 1);
} }
if (info) {
fb_dealloc_cmap(&info->cmap); fb_dealloc_cmap(&info->cmap);
framebuffer_release(info); framebuffer_release(info);
}
return ret; return ret;
} }
......
...@@ -577,10 +577,8 @@ static int lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -577,10 +577,8 @@ static int lxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_release_region(pdev, 3); pci_release_region(pdev, 3);
} }
if (info) {
fb_dealloc_cmap(&info->cmap); fb_dealloc_cmap(&info->cmap);
framebuffer_release(info); framebuffer_release(info);
}
return ret; return ret;
} }
......
...@@ -417,8 +417,7 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var, ...@@ -417,8 +417,7 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info) struct fb_info *info)
{ {
if (var->vmode & FB_VMODE_YWRAP) { if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset < 0 || if (var->yoffset >= info->var.yres_virtual ||
var->yoffset >= info->var.yres_virtual ||
var->xoffset) var->xoffset)
return -EINVAL; return -EINVAL;
} else { } 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 if MMP_DISP
config MMP_FB config MMP_FB
bool "fb driver for Marvell MMP Display Subsystem" tristate "fb driver for Marvell MMP Display Subsystem"
depends on FB depends on FB
select FB_CFB_FILLRECT select FB_CFB_FILLRECT
select FB_CFB_COPYAREA select FB_CFB_COPYAREA
......
...@@ -61,7 +61,7 @@ struct ocfb_dev { ...@@ -61,7 +61,7 @@ struct ocfb_dev {
/* flag indicating whether the regs are little endian accessed */ /* flag indicating whether the regs are little endian accessed */
int little_endian; int little_endian;
/* Physical and virtual addresses of framebuffer */ /* Physical and virtual addresses of framebuffer */
phys_addr_t fb_phys; dma_addr_t fb_phys;
void __iomem *fb_virt; void __iomem *fb_virt;
u32 pseudo_palette[PALETTE_SIZE]; u32 pseudo_palette[PALETTE_SIZE];
}; };
......
menu "OMAP Display Device Drivers (new device model)" menu "OMAP Display Device Drivers (new device model)"
depends on OMAP2_DSS 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 config DISPLAY_ENCODER_TFP410
tristate "TFP410 DPI to DVI Encoder" tristate "TFP410 DPI to DVI Encoder"
help help
......
obj-$(CONFIG_DISPLAY_ENCODER_OPA362) += encoder-opa362.o
obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
......
...@@ -208,7 +208,7 @@ static int tvc_probe_pdata(struct platform_device *pdev) ...@@ -208,7 +208,7 @@ static int tvc_probe_pdata(struct platform_device *pdev)
ddata->in = in; ddata->in = in;
ddata->connector_type = pdata->connector_type; ddata->connector_type = pdata->connector_type;
ddata->invert_polarity = ddata->invert_polarity; ddata->invert_polarity = pdata->invert_polarity;
dssdev = &ddata->dssdev; dssdev = &ddata->dssdev;
dssdev->name = pdata->name; 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 { ...@@ -29,33 +29,10 @@ struct panel_drv_data {
int hpd_gpio; int hpd_gpio;
struct omap_video_timings timings; struct omap_video_timings timings;
struct completion hpd_completion;
}; };
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) #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, static int tpd_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst) struct omap_dss_device *dst)
{ {
...@@ -70,23 +47,10 @@ static int tpd_connect(struct omap_dss_device *dssdev, ...@@ -70,23 +47,10 @@ static int tpd_connect(struct omap_dss_device *dssdev,
dst->src = dssdev; dst->src = dssdev;
dssdev->dst = dst; dssdev->dst = dst;
reinit_completion(&ddata->hpd_completion);
gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1); gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
/* DC-DC converter needs at max 300us to get to 90% of 5V */ /* DC-DC converter needs at max 300us to get to 90% of 5V */
udelay(300); 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; return 0;
} }
...@@ -179,11 +143,20 @@ static int tpd_read_edid(struct omap_dss_device *dssdev, ...@@ -179,11 +143,20 @@ static int tpd_read_edid(struct omap_dss_device *dssdev,
{ {
struct panel_drv_data *ddata = to_panel_data(dssdev); struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in; struct omap_dss_device *in = ddata->in;
int r;
if (!gpio_get_value_cansleep(ddata->hpd_gpio)) if (!gpio_get_value_cansleep(ddata->hpd_gpio))
return -ENODEV; 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) static bool tpd_detect(struct omap_dss_device *dssdev)
...@@ -309,8 +282,6 @@ static int tpd_probe(struct platform_device *pdev) ...@@ -309,8 +282,6 @@ static int tpd_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ddata); platform_set_drvdata(pdev, ddata);
init_completion(&ddata->hpd_completion);
if (dev_get_platdata(&pdev->dev)) { if (dev_get_platdata(&pdev->dev)) {
r = tpd_probe_pdata(pdev); r = tpd_probe_pdata(pdev);
if (r) if (r)
...@@ -340,13 +311,6 @@ static int tpd_probe(struct platform_device *pdev) ...@@ -340,13 +311,6 @@ static int tpd_probe(struct platform_device *pdev)
if (r) if (r)
goto err_gpio; 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 = &ddata->dssdev;
dssdev->ops.hdmi = &tpd_hdmi_ops; dssdev->ops.hdmi = &tpd_hdmi_ops;
dssdev->dev = &pdev->dev; dssdev->dev = &pdev->dev;
...@@ -365,7 +329,6 @@ static int tpd_probe(struct platform_device *pdev) ...@@ -365,7 +329,6 @@ static int tpd_probe(struct platform_device *pdev)
return 0; return 0;
err_reg: err_reg:
err_irq:
err_gpio: err_gpio:
omap_dss_put_device(ddata->in); omap_dss_put_device(ddata->in);
return r; return r;
......
...@@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o ...@@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
obj-$(CONFIG_OMAP2_DSS) += omapdss.o obj-$(CONFIG_OMAP2_DSS) += omapdss.o
# Core DSS files # Core DSS files
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ 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 # DSS compat layer files
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
dispc-compat.o display-sysfs.o dispc-compat.o display-sysfs.o
......
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/of.h>
#include <video/omapdss.h> #include <video/omapdss.h>
...@@ -117,6 +120,9 @@ static struct { ...@@ -117,6 +120,9 @@ static struct {
const struct dispc_features *feat; const struct dispc_features *feat;
bool is_enabled; bool is_enabled;
struct regmap *syscon_pol;
u32 syscon_pol_offset;
} dispc; } dispc;
enum omap_color_component { enum omap_color_component {
...@@ -2958,6 +2964,25 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, ...@@ -2958,6 +2964,25 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
FLD_VAL(vsync_level, 12, 12); FLD_VAL(vsync_level, 12, 12);
dispc_write_reg(DISPC_POL_FREQ(channel), l); 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? */ /* change name to mode? */
...@@ -3037,10 +3062,16 @@ unsigned long dispc_fclk_rate(void) ...@@ -3037,10 +3062,16 @@ unsigned long dispc_fclk_rate(void)
break; break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi0"); pll = dss_pll_find("dsi0");
if (!pll)
pll = dss_pll_find("video0");
r = pll->cinfo.clkout[0]; r = pll->cinfo.clkout[0];
break; break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi1"); pll = dss_pll_find("dsi1");
if (!pll)
pll = dss_pll_find("video1");
r = pll->cinfo.clkout[0]; r = pll->cinfo.clkout[0];
break; break;
default: default:
...@@ -3069,10 +3100,16 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) ...@@ -3069,10 +3100,16 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
break; break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi0"); pll = dss_pll_find("dsi0");
if (!pll)
pll = dss_pll_find("video0");
r = pll->cinfo.clkout[0]; r = pll->cinfo.clkout[0];
break; break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi1"); pll = dss_pll_find("dsi1");
if (!pll)
pll = dss_pll_find("video1");
r = pll->cinfo.clkout[0]; r = pll->cinfo.clkout[0];
break; break;
default: default:
...@@ -3668,6 +3705,7 @@ static int __init dispc_init_features(struct platform_device *pdev) ...@@ -3668,6 +3705,7 @@ static int __init dispc_init_features(struct platform_device *pdev)
break; break;
case OMAPDSS_VER_OMAP5: case OMAPDSS_VER_OMAP5:
case OMAPDSS_VER_DRA7xx:
src = &omap54xx_dispc_feats; src = &omap54xx_dispc_feats;
break; break;
...@@ -3728,6 +3766,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) ...@@ -3728,6 +3766,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
u32 rev; u32 rev;
int r = 0; int r = 0;
struct resource *dispc_mem; struct resource *dispc_mem;
struct device_node *np = pdev->dev.of_node;
dispc.pdev = pdev; dispc.pdev = pdev;
...@@ -3754,6 +3793,20 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) ...@@ -3754,6 +3793,20 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
return -ENODEV; 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); pm_runtime_enable(&pdev->dev);
r = dispc_runtime_get(); r = dispc_runtime_get();
...@@ -3832,6 +3885,7 @@ static const struct of_device_id dispc_of_match[] = { ...@@ -3832,6 +3885,7 @@ static const struct of_device_id dispc_of_match[] = {
{ .compatible = "ti,omap3-dispc", }, { .compatible = "ti,omap3-dispc", },
{ .compatible = "ti,omap4-dispc", }, { .compatible = "ti,omap4-dispc", },
{ .compatible = "ti,omap5-dispc", }, { .compatible = "ti,omap5-dispc", },
{ .compatible = "ti,dra7-dispc", },
{}, {},
}; };
......
...@@ -106,6 +106,17 @@ static struct dss_pll *dpi_get_pll(enum omap_channel channel) ...@@ -106,6 +106,17 @@ static struct dss_pll *dpi_get_pll(enum omap_channel channel)
return NULL; 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: default:
return NULL; return NULL;
} }
...@@ -590,6 +601,10 @@ static void dpi_init_pll(struct dpi_data *dpi) ...@@ -590,6 +601,10 @@ static void dpi_init_pll(struct dpi_data *dpi)
if (!pll) if (!pll)
return; 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)) { if (dpi_verify_dsi_pll(pll)) {
DSSWARN("DSI PLL not operational\n"); DSSWARN("DSI PLL not operational\n");
return; return;
...@@ -615,6 +630,17 @@ static enum omap_channel dpi_get_channel(int port_num) ...@@ -615,6 +630,17 @@ static enum omap_channel dpi_get_channel(int port_num)
case OMAPDSS_VER_AM43xx: case OMAPDSS_VER_AM43xx:
return OMAP_DSS_CHANNEL_LCD; 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_ES1:
case OMAPDSS_VER_OMAP4430_ES2: case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4: case OMAPDSS_VER_OMAP4:
......
...@@ -5238,6 +5238,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev) ...@@ -5238,6 +5238,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev)
} }
pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1"; pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1";
pll->id = dsi->module_id == 0 ? DSS_PLL_DSI1 : DSS_PLL_DSI2;
pll->clkin = clk; pll->clkin = clk;
pll->base = dsi->pll_base; pll->base = dsi->pll_base;
......
...@@ -34,7 +34,10 @@ ...@@ -34,7 +34,10 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <video/omapdss.h> #include <video/omapdss.h>
...@@ -63,14 +66,11 @@ struct dss_reg { ...@@ -63,14 +66,11 @@ struct dss_reg {
#define REG_FLD_MOD(idx, val, start, end) \ #define REG_FLD_MOD(idx, val, start, end) \
dss_write_reg(idx, FLD_MOD(dss_read_reg(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 { struct dss_features {
u8 fck_div_max; u8 fck_div_max;
u8 dss_fck_multiplier; u8 dss_fck_multiplier;
const char *parent_clk_name; const char *parent_clk_name;
enum omap_display_type *ports; const enum omap_display_type *ports;
int num_ports; int num_ports;
int (*dpi_select_source)(int port, enum omap_channel channel); int (*dpi_select_source)(int port, enum omap_channel channel);
}; };
...@@ -78,6 +78,8 @@ struct dss_features { ...@@ -78,6 +78,8 @@ struct dss_features {
static struct { static struct {
struct platform_device *pdev; struct platform_device *pdev;
void __iomem *base; void __iomem *base;
struct regmap *syscon_pll_ctrl;
u32 syscon_pll_ctrl_offset;
struct clk *parent_clk; struct clk *parent_clk;
struct clk *dss_clk; struct clk *dss_clk;
...@@ -95,6 +97,9 @@ static struct { ...@@ -95,6 +97,9 @@ static struct {
u32 ctx[DSS_SZ_REGS / sizeof(u32)]; u32 ctx[DSS_SZ_REGS / sizeof(u32)];
const struct dss_features *feat; const struct dss_features *feat;
struct dss_pll *video1_pll;
struct dss_pll *video2_pll;
} dss; } dss;
static const char * const dss_generic_clk_source_names[] = { static const char * const dss_generic_clk_source_names[] = {
...@@ -158,6 +163,99 @@ static void dss_restore_context(void) ...@@ -158,6 +163,99 @@ static void dss_restore_context(void)
#undef SR #undef SR
#undef RR #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) void dss_sdi_init(int datapairs)
{ {
u32 l; u32 l;
...@@ -605,6 +703,26 @@ static int dss_dpi_select_source_omap5(int port, enum omap_channel channel) ...@@ -605,6 +703,26 @@ static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
return 0; 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) int dss_dpi_select_source(int port, enum omap_channel channel)
{ {
return dss.feat->dpi_select_source(port, channel); return dss.feat->dpi_select_source(port, channel);
...@@ -643,7 +761,7 @@ static void dss_put_clocks(void) ...@@ -643,7 +761,7 @@ static void dss_put_clocks(void)
clk_put(dss.parent_clk); clk_put(dss.parent_clk);
} }
static int dss_runtime_get(void) int dss_runtime_get(void)
{ {
int r; int r;
...@@ -654,7 +772,7 @@ static int dss_runtime_get(void) ...@@ -654,7 +772,7 @@ static int dss_runtime_get(void)
return r < 0 ? r : 0; return r < 0 ? r : 0;
} }
static void dss_runtime_put(void) void dss_runtime_put(void)
{ {
int r; int r;
...@@ -677,15 +795,21 @@ void dss_debug_dump_clocks(struct seq_file *s) ...@@ -677,15 +795,21 @@ void dss_debug_dump_clocks(struct seq_file *s)
#endif #endif
static enum omap_display_type omap2plus_ports[] = { static const enum omap_display_type omap2plus_ports[] = {
OMAP_DISPLAY_TYPE_DPI, 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_DPI,
OMAP_DISPLAY_TYPE_SDI, 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 = { static const struct dss_features omap24xx_dss_feats __initconst = {
/* /*
* fck div max is really 16, but the divider range has gaps. The range * 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 = { ...@@ -744,6 +868,15 @@ static const struct dss_features am43xx_dss_feats __initconst = {
.num_ports = ARRAY_SIZE(omap2plus_ports), .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) static int __init dss_init_features(struct platform_device *pdev)
{ {
const struct dss_features *src; const struct dss_features *src;
...@@ -784,6 +917,10 @@ static int __init dss_init_features(struct platform_device *pdev) ...@@ -784,6 +917,10 @@ static int __init dss_init_features(struct platform_device *pdev)
src = &am43xx_dss_feats; src = &am43xx_dss_feats;
break; break;
case OMAPDSS_VER_DRA7xx:
src = &dra7xx_dss_feats;
break;
default: default:
return -ENODEV; return -ENODEV;
} }
...@@ -884,8 +1021,10 @@ static void __exit dss_uninit_ports(struct platform_device *pdev) ...@@ -884,8 +1021,10 @@ static void __exit dss_uninit_ports(struct platform_device *pdev)
static int __init omap_dsshw_probe(struct platform_device *pdev) static int __init omap_dsshw_probe(struct platform_device *pdev)
{ {
struct resource *dss_mem; struct resource *dss_mem;
struct device_node *np = pdev->dev.of_node;
u32 rev; u32 rev;
int r; int r;
struct regulator *pll_regulator;
dss.pdev = pdev; dss.pdev = pdev;
...@@ -940,6 +1079,57 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) ...@@ -940,6 +1079,57 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
dss_init_ports(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); rev = dss_read_reg(DSS_REVISION);
printk(KERN_INFO "OMAP DSS rev %d.%d\n", printk(KERN_INFO "OMAP DSS rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
...@@ -950,6 +1140,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) ...@@ -950,6 +1140,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
return 0; 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: err_runtime_get:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
err_setup_clocks: err_setup_clocks:
...@@ -959,6 +1155,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) ...@@ -959,6 +1155,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
static int __exit omap_dsshw_remove(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); dss_uninit_ports(pdev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
...@@ -1003,6 +1205,7 @@ static const struct of_device_id dss_of_match[] = { ...@@ -1003,6 +1205,7 @@ static const struct of_device_id dss_of_match[] = {
{ .compatible = "ti,omap3-dss", }, { .compatible = "ti,omap3-dss", },
{ .compatible = "ti,omap4-dss", }, { .compatible = "ti,omap4-dss", },
{ .compatible = "ti,omap5-dss", }, { .compatible = "ti,omap5-dss", },
{ .compatible = "ti,dra7-dss", },
{}, {},
}; };
......
...@@ -100,6 +100,14 @@ enum dss_writeback_channel { ...@@ -100,6 +100,14 @@ enum dss_writeback_channel {
DSS_WB_LCD3_MGR = 7, 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; struct dss_pll;
#define DSS_PLL_MAX_HSDIVS 4 #define DSS_PLL_MAX_HSDIVS 4
...@@ -150,6 +158,7 @@ struct dss_pll_hw { ...@@ -150,6 +158,7 @@ struct dss_pll_hw {
struct dss_pll { struct dss_pll {
const char *name; const char *name;
enum dss_pll_id id;
struct clk *clkin; struct clk *clkin;
struct regulator *regulator; struct regulator *regulator;
...@@ -250,6 +259,9 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl); ...@@ -250,6 +259,9 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
int dss_init_platform_driver(void) __init; int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void); void dss_uninit_platform_driver(void);
int dss_runtime_get(void);
void dss_runtime_put(void);
unsigned long dss_get_dispc_clk_rate(void); unsigned long dss_get_dispc_clk_rate(void);
int dss_dpi_select_source(int port, enum omap_channel channel); 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); 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); ...@@ -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); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
void dss_dump_clocks(struct seq_file *s); 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 */ /* dss-of */
struct device_node *dss_of_port_get_parent_device(struct device_node *port); struct device_node *dss_of_port_get_parent_device(struct device_node *port);
u32 dss_of_port_get_port_number(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); ...@@ -265,6 +282,10 @@ u32 dss_of_port_get_port_number(struct device_node *port);
void dss_debug_dump_clocks(struct seq_file *s); void dss_debug_dump_clocks(struct seq_file *s);
#endif #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); void dss_sdi_init(int datapairs);
int dss_sdi_enable(void); int dss_sdi_enable(void);
void dss_sdi_disable(void); void dss_sdi_disable(void);
...@@ -446,5 +467,6 @@ int dss_pll_write_config_type_a(struct dss_pll *pll, ...@@ -446,5 +467,6 @@ int dss_pll_write_config_type_a(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo); const struct dss_pll_clock_info *cinfo);
int dss_pll_write_config_type_b(struct dss_pll *pll, int dss_pll_write_config_type_b(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo); const struct dss_pll_clock_info *cinfo);
int dss_pll_wait_reset_done(struct dss_pll *pll);
#endif #endif
...@@ -223,7 +223,7 @@ static const enum omap_dss_output_id omap5_dss_supported_outputs[] = { ...@@ -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_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
/* OMAP_DSS_CHANNEL_DIGIT */ /* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI, OMAP_DSS_OUTPUT_HDMI,
/* OMAP_DSS_CHANNEL_LCD2 */ /* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
...@@ -943,6 +943,7 @@ void dss_features_init(enum omapdss_version version) ...@@ -943,6 +943,7 @@ void dss_features_init(enum omapdss_version version)
break; break;
case OMAPDSS_VER_OMAP5: case OMAPDSS_VER_OMAP5:
case OMAPDSS_VER_DRA7xx:
omap_current_dss_features = &omap5_dss_features; omap_current_dss_features = &omap5_dss_features;
break; break;
......
...@@ -787,6 +787,7 @@ static const struct dev_pm_ops hdmi_pm_ops = { ...@@ -787,6 +787,7 @@ static const struct dev_pm_ops hdmi_pm_ops = {
static const struct of_device_id hdmi_of_match[] = { static const struct of_device_id hdmi_of_match[] = {
{ .compatible = "ti,omap5-hdmi", }, { .compatible = "ti,omap5-hdmi", },
{ .compatible = "ti,dra7-hdmi", },
{}, {},
}; };
......
...@@ -208,6 +208,7 @@ static int hdmi_phy_init_features(struct platform_device *pdev) ...@@ -208,6 +208,7 @@ static int hdmi_phy_init_features(struct platform_device *pdev)
break; break;
case OMAPDSS_VER_OMAP5: case OMAPDSS_VER_OMAP5:
case OMAPDSS_VER_DRA7xx:
src = &omap54xx_phy_feats; src = &omap54xx_phy_feats;
break; break;
......
...@@ -104,6 +104,8 @@ static int hdmi_pll_enable(struct dss_pll *dsspll) ...@@ -104,6 +104,8 @@ static int hdmi_pll_enable(struct dss_pll *dsspll)
struct hdmi_wp_data *wp = pll->wp; struct hdmi_wp_data *wp = pll->wp;
u16 r = 0; u16 r = 0;
dss_ctrl_pll_enable(DSS_PLL_HDMI, true);
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
if (r) if (r)
return r; return r;
...@@ -117,6 +119,8 @@ static void hdmi_pll_disable(struct dss_pll *dsspll) ...@@ -117,6 +119,8 @@ static void hdmi_pll_disable(struct dss_pll *dsspll)
struct hdmi_wp_data *wp = pll->wp; struct hdmi_wp_data *wp = pll->wp;
hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); 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 = { 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 ...@@ -185,6 +189,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data
} }
pll->name = "hdmi"; pll->name = "hdmi";
pll->id = DSS_PLL_HDMI;
pll->base = hpll->base; pll->base = hpll->base;
pll->clkin = clk; pll->clkin = clk;
...@@ -196,6 +201,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data ...@@ -196,6 +201,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data
break; break;
case OMAPDSS_VER_OMAP5: case OMAPDSS_VER_OMAP5:
case OMAPDSS_VER_DRA7xx:
pll->hw = &dss_omap5_hdmi_pll_hw; pll->hw = &dss_omap5_hdmi_pll_hw;
break; break;
......
...@@ -186,6 +186,7 @@ static const struct of_device_id omapdss_of_match[] __initconst = { ...@@ -186,6 +186,7 @@ static const struct of_device_id omapdss_of_match[] __initconst = {
{ .compatible = "ti,omap3-dss", }, { .compatible = "ti,omap3-dss", },
{ .compatible = "ti,omap4-dss", }, { .compatible = "ti,omap4-dss", },
{ .compatible = "ti,omap5-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) ...@@ -222,6 +222,16 @@ static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
return !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) static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
{ {
int t = 100; 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) ...@@ -137,8 +137,11 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
goto undo; goto undo;
} }
if (ovl->manager) if (ovl->manager) {
ovl->manager->apply(ovl->manager); r = ovl->manager->apply(ovl->manager);
if (r)
goto undo;
}
if (pi->enabled) { if (pi->enabled) {
r = ovl->enable(ovl); r = ovl->enable(ovl);
......
...@@ -351,32 +351,26 @@ static inline void VGAwSEQ(u8 index, u8 val, struct savagefb_par *par) ...@@ -351,32 +351,26 @@ static inline void VGAwSEQ(u8 index, u8 val, struct savagefb_par *par)
static inline void VGAenablePalette(struct savagefb_par *par) static inline void VGAenablePalette(struct savagefb_par *par)
{ {
u8 tmp; vga_in8(0x3da, par);
tmp = vga_in8(0x3da, par);
vga_out8(0x3c0, 0x00, par); vga_out8(0x3c0, 0x00, par);
par->paletteEnabled = 1; par->paletteEnabled = 1;
} }
static inline void VGAdisablePalette(struct savagefb_par *par) static inline void VGAdisablePalette(struct savagefb_par *par)
{ {
u8 tmp; vga_in8(0x3da, par);
tmp = vga_in8(0x3da, par);
vga_out8(0x3c0, 0x20, par); vga_out8(0x3c0, 0x20, par);
par->paletteEnabled = 0; par->paletteEnabled = 0;
} }
static inline void VGAwATTR(u8 index, u8 value, struct savagefb_par *par) static inline void VGAwATTR(u8 index, u8 value, struct savagefb_par *par)
{ {
u8 tmp;
if (par->paletteEnabled) if (par->paletteEnabled)
index &= ~0x20; index &= ~0x20;
else else
index |= 0x20; index |= 0x20;
tmp = vga_in8(0x3da, par); vga_in8(0x3da, par);
vga_out8(0x3c0, index, par); vga_out8(0x3c0, index, par);
vga_out8 (0x3c0, value, par); vga_out8 (0x3c0, value, par);
} }
......
...@@ -122,23 +122,6 @@ static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd) ...@@ -122,23 +122,6 @@ static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
return ret; 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) static void ssd1307fb_update_display(struct ssd1307fb_par *par)
{ {
struct ssd1307fb_array *array; struct ssd1307fb_array *array;
...@@ -320,7 +303,10 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par) ...@@ -320,7 +303,10 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
/* Set initial contrast */ /* Set initial contrast */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_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) if (ret < 0)
return ret; return ret;
...@@ -336,62 +322,98 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par) ...@@ -336,62 +322,98 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
/* Set multiplex ratio value */ /* Set multiplex ratio value */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO); 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) if (ret < 0)
return ret; return ret;
/* set display offset value */ /* set display offset value */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET); ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, 0x20); ret = ssd1307fb_write_cmd(par->client, 0x20);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* Set clock frequency */ /* Set clock frequency */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ); 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) if (ret < 0)
return ret; return ret;
/* Set precharge period in number of ticks from the internal clock */ /* Set precharge period in number of ticks from the internal clock */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD); 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) if (ret < 0)
return ret; return ret;
/* Set COM pins configuration */ /* Set COM pins configuration */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG); 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) if (ret < 0)
return ret; return ret;
/* Set VCOMH */ /* Set VCOMH */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_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) if (ret < 0)
return ret; return ret;
/* Turn on the DC-DC Charge Pump */ /* Turn on the DC-DC Charge Pump */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_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) if (ret < 0)
return ret; return ret;
/* Switch to horizontal addressing mode */ /* Switch to horizontal addressing mode */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE); ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
ret = ret & ssd1307fb_write_cmd(par->client, if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client,
SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL); SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE); ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
ret = ret & ssd1307fb_write_cmd(par->client, 0x0); if (ret < 0)
ret = ret & ssd1307fb_write_cmd(par->client, par->width - 1); 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) if (ret < 0)
return ret; return ret;
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE); ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
ret = ret & ssd1307fb_write_cmd(par->client, 0x0); if (ret < 0)
ret = ret & ssd1307fb_write_cmd(par->client, 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); par->page_offset + (par->height / 8) - 1);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -460,7 +482,7 @@ static int ssd1307fb_probe(struct i2c_client *client, ...@@ -460,7 +482,7 @@ static int ssd1307fb_probe(struct i2c_client *client,
par->width = 96; par->width = 96;
if (of_property_read_u32(node, "solomon,height", &par->height)) 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)) if (of_property_read_u32(node, "solomon,page-offset", &par->page_offset))
par->page_offset = 1; par->page_offset = 1;
......
...@@ -113,10 +113,8 @@ static int vt8500lcd_set_par(struct fb_info *info) ...@@ -113,10 +113,8 @@ static int vt8500lcd_set_par(struct fb_info *info)
} }
for (i = 0; i < 8; i++) { 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; reg_bpp = i;
continue;
}
} }
control0 = readl(fbi->regbase) & ~0xf; control0 = readl(fbi->regbase) & ~0xf;
......
...@@ -726,7 +726,9 @@ extern int fb_videomode_from_videomode(const struct videomode *vm, ...@@ -726,7 +726,9 @@ extern int fb_videomode_from_videomode(const struct videomode *vm,
struct fb_videomode *fbmode); struct fb_videomode *fbmode);
/* drivers/video/modedb.c */ /* 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, extern void fb_var_to_videomode(struct fb_videomode *mode,
const struct fb_var_screeninfo *var); const struct fb_var_screeninfo *var);
extern void fb_videomode_to_var(struct fb_var_screeninfo *var, extern void fb_videomode_to_var(struct fb_var_screeninfo *var,
...@@ -777,9 +779,17 @@ struct fb_videomode { ...@@ -777,9 +779,17 @@ struct fb_videomode {
u32 flag; 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 char *fb_mode_option;
extern const struct fb_videomode vesa_modes[]; extern const struct fb_videomode vesa_modes[];
extern const struct fb_videomode cea_modes[64]; extern const struct fb_videomode cea_modes[64];
extern const struct dmt_videomode dmt_modes[];
struct fb_modelist { struct fb_modelist {
struct list_head list; struct list_head list;
......
...@@ -314,6 +314,7 @@ enum omapdss_version { ...@@ -314,6 +314,7 @@ enum omapdss_version {
OMAPDSS_VER_OMAP4, /* All other OMAP4s */ OMAPDSS_VER_OMAP4, /* All other OMAP4s */
OMAPDSS_VER_OMAP5, OMAPDSS_VER_OMAP5,
OMAPDSS_VER_AM43xx, OMAPDSS_VER_AM43xx,
OMAPDSS_VER_DRA7xx,
}; };
/* Board specific data */ /* 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