I've attached three patches for consideration in the Robert Nelson's 
3.8.13-bone5x update, all of which are independent of each other (i.e., you 
can patch your kernel with any one of them, separate from the others):

0001-am335x-features

Detect AM335x-specific features and CPU version. Doesn't do anything 
significant, other than accurately report the CPU and SGX, L2 cache 
presence in the bootup dmesg output.


0002-element14-bb-view-lcd-capes

 Add Element14's "BB-VIEW" LCD cape device trees to firmware/capes.


0003-sitara_rb_swap_workaround

Create a workaround to the TI Sitara red/blue swap erratum through device 
tree properties, 'bgrx_16bpp' and 'bgrx_24bpp'. The 'bgrx_16bpp' property 
swaps red and blue if 16bpp color depth is used and the LCD cape itself 
swaps red and blue at higher color depths (i.e., the cape designer "fixed" 
the problem by swapping signals). The 'bgrx_24bpp' property swaps red and 
blue at the 24bpp color depth, which addresses TI's erratum.


Also, the tilcdc LCD driver queries the panel's panel-info/bpp device tree 
property to find the preferred BPP when initializing the console 
framebuffer. This was originally hardcoded into the driver at 16bpp. If the 
panel says that it wants 32bpp, the framebuffer initializes to a preferred 
32bpp.


I've been testing these changes relative to Robert's linux-dev 
3.8.15-bone53 tag. They may apply cleanly against earlier tags, but I can't 
guarantee they will.

I'm sure I have canonical kernel source formatting issues; comments, 
testing and suggestions are welcome (and advocacy for inclusion in Robert's 
linux-dev git repo also helpful.)


-scooter

 

-- 
For more options, visit http://beagleboard.org/discuss
--- 
You received this message because you are subscribed to the Google Groups 
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
commit 06f24dee9ba97e9dd3f2fff843b442aafe5f76e4
Author: B. Scott Michel <[email protected]>
Date:   Thu May 29 09:56:48 2014 -0700

    am335x_feature_detection
    
    Identify AM335x chip versions, detect and enable chip-specific
    features such as the SGX GPU's presence and L2 cache.

diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index 12d8468..7adefd4 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -402,6 +402,12 @@
 #define		FEAT_NEON_NONE		1
 
 
+/* AM335X DEV_FEATURES register */
+#define AM335X_DEV_FEATURES				0x604
+
+#define AM335X_SGX_SHIFT		29
+#define AM335X_SGX_MASK			(1 << AM335X_SGX_SHIFT)
+
 #ifndef __ASSEMBLY__
 #ifdef CONFIG_ARCH_OMAP2PLUS
 extern void __iomem *omap_ctrl_base_get(void);
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 45cc7ed4..9486a02 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -289,6 +289,29 @@ void __init ti81xx_check_features(void)
 	omap3_cpuinfo();
 }
 
+void __init am33xx_check_features(void)
+{
+	omap_features = OMAP3_HAS_NEON;
+
+        /*
+	 * am335x() fixups:
+	 * - The DEV_FEATURES register knows whether the SoC has SGX.
+	 */
+	if (soc_is_am335x()) {
+		u32 status;
+
+		status = omap_ctrl_readl(AM335X_DEV_FEATURES);
+
+		if (((status & AM335X_SGX_MASK) >> AM335X_SGX_SHIFT) == 1) {
+			omap_features |= OMAP3_HAS_SGX;
+		}
+
+		omap_features |= OMAP3_HAS_L2CACHE;
+	}
+
+	omap3_cpuinfo();
+}
+
 void __init omap3xxx_check_revision(void)
 {
 	u32 cpuid, idcode;
@@ -399,8 +422,25 @@ void __init omap3xxx_check_revision(void)
 		}
 		break;
 	case 0xb944:
-		omap_revision = AM335X_REV_ES1_0;
-		cpu_rev = "1.0";
+		switch (rev) {
+		case 0:
+			omap_revision = AM335X_REV_ES1_0;
+			cpu_rev = "1.0";
+			break;
+		case 1:
+			omap_revision = AM335X_REV_ES2_0;
+			cpu_rev = "2.0";
+			break;
+		case 2:
+			omap_revision = AM335X_REV_ES2_1;
+			cpu_rev = "2.1";
+			break;
+		default:
+			/* Assume 1.0 silicon errata if invalid. */
+			omap_revision = AM335X_REV_ES1_0;
+			cpu_rev = "1.0";
+			break;
+		}
 		break;
 	case 0xb8f2:
 		switch (rev) {
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 5c445ca..522864c 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -568,7 +568,7 @@ void __init am33xx_init_early(void)
 	omap2_set_globals_prm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE));
 	omap2_set_globals_cm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE), NULL);
 	omap3xxx_check_revision();
-	ti81xx_check_features();
+	am33xx_check_features();
 	am33xx_voltagedomains_init();
 	am33xx_powerdomains_init();
 	am33xx_clockdomains_init();
diff --git a/arch/arm/mach-omap2/soc.h b/arch/arm/mach-omap2/soc.h
index f31d907..068893e 100644
--- a/arch/arm/mach-omap2/soc.h
+++ b/arch/arm/mach-omap2/soc.h
@@ -387,6 +387,8 @@ IS_OMAP_TYPE(3430, 0x3430)
 
 #define AM335X_CLASS		0x33500033
 #define AM335X_REV_ES1_0	AM335X_CLASS
+#define AM335X_REV_ES2_0	(AM335X_CLASS | (0x1 << 8))
+#define AM335X_REV_ES2_1	(AM335X_CLASS | (0x2 << 8))
 
 #define OMAP443X_CLASS		0x44300044
 #define OMAP4430_REV_ES1_0	(OMAP443X_CLASS | (0x10 << 8))
@@ -412,6 +414,7 @@ void omap4xxx_check_revision(void);
 void omap5xxx_check_revision(void);
 void omap3xxx_check_features(void);
 void ti81xx_check_features(void);
+void am33xx_check_features(void);
 void omap4xxx_check_features(void);
 
 /*
commit b45f4110ae28df6a25c445f905a768a8ed31ce1f
Author: B. Scott Michel <[email protected]>
Date:   Thu May 29 11:29:39 2014 -0700

    element14_bb_view_lcd_capes
    
    Add device tree source for Element14's "BB-VIEW" series of LCD
    capes.

diff --git a/firmware/Makefile b/firmware/Makefile
index b1c6ab9..ceac419 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -211,7 +211,9 @@ fw-shipped-$(CONFIG_CAPE_BEAGLEBONE) += \
 	bone_eqep0-00A0.dtbo \
 	bone_eqep1-00A0.dtbo \
 	bone_eqep2-00A0.dtbo \
-	BB-BONE-LOGIBONE-00R1.dtbo
+	BB-BONE-LOGIBONE-00R1.dtbo \
+	BB-VIEW-LCD4-01-00A0.dtbo \
+	BB-VIEW-LCD7-01-00A0.dtbo
 
 # the geiger cape
 fw-shipped-$(CONFIG_CAPE_BEAGLEBONE_GEIGER) += \
diff --git a/firmware/capes/BB-VIEW-LCD4-01-00A0.dts b/firmware/capes/BB-VIEW-LCD4-01-00A0.dts
new file mode 100644
index 0000000..ea6ba64
--- /dev/null
+++ b/firmware/capes/BB-VIEW-LCD4-01-00A0.dts
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.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.
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "ti,beaglebone", "ti,beaglebone-black";
+
+	/* identification */
+	part-number = "BB-VIEW-LCD4-01";
+	version = "00A0";
+
+	/* state the resources this cape uses */
+	exclusive-use =
+		/* the pin header uses */
+		"P8.45",	/* lcd: lcd_data0 */
+		"P8.46",	/* lcd: lcd_data1 */
+		"P8.43",	/* lcd: lcd_data2 */
+		"P8.44",	/* lcd: lcd_data3 */
+		"P8.41",	/* lcd: lcd_data4 */
+		"P8.42",	/* lcd: lcd_data5 */
+		"P8.39",	/* lcd: lcd_data6 */
+		"P8.40",	/* lcd: lcd_data7 */
+		"P8.37",	/* lcd: lcd_data8 */
+		"P8.38",	/* lcd: lcd_data9 */
+		"P8.36",	/* lcd: lcd_data10 */
+		"P8.34",	/* lcd: lcd_data11 */
+		"P8.35",	/* lcd: lcd_data12 */
+		"P8.33",	/* lcd: lcd_data13 */
+		"P8.31",	/* lcd: lcd_data14 */
+		"P8.32",	/* lcd: lcd_data15 */
+		"P8.27",	/* lcd: lcd_vsync */
+		"P8.29",	/* lcd: lcd_hsync */
+		"P8.28",	/* lcd: lcd_pclk */
+		"P8.30",	/* lcd: lcd_ac_bias_en */
+		"P9.27",	/* lcd: gpio3_19 */
+		"P9.12",	/* led: gpio1_28 */
+		"P9.14",	/* pwm: ehrpwm1a */
+		"P9.15",	/* keys: gpio1_16 */
+		"P9.23",	/* keys: gpio1_17 */
+		"P9.16",	/* keys: gpio1_19 */
+		"P9.21",	/* keys: gpio0_3 */
+		/* the hardware IP uses */
+		"gpio3_19",
+		"gpio1_28",
+		"gpio1_16",
+		"gpio1_17",
+		"gpio1_19",
+		"gpio0_3",
+		/* "gpio0_12", */
+		"lcd",
+		"ehrpwm1a";
+
+	fragment@0 {
+		target = <&am33xx_pinmux>;
+		__overlay__ {
+
+			bb_view_lcd_cape_led_pins: pinmux_bb_view_lcd_cape_led_pins {
+				pinctrl-single,pins = <
+					0x078 0x2f      /* gpmc_be1n.gpio1_28, INPUT | PULLDIS | MODE7 */
+					/* 0x178 0x2f	 * uart1_ctsn.gpio0_12,INPUT | PULLDIS | MODE7 */
+				>;
+			};
+
+			pwm_bl_pins: pinmux_pwm_bl_pins {
+				pinctrl-single,pins = <
+					0x48 0x06       /* gpmc_a2.ehrpwm1a, OMAP_MUX_MODE6 | AM33XX_PIN_OUTPUT */
+				>;
+			};
+
+			bb_view_lcd_cape_pins: pinmux_bb_view_lcd_cape_pins {
+				pinctrl-single,pins = <
+					0xa0 0x08	/* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xa4 0x08	/* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xa8 0x08	/* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xac 0x08	/* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xb0 0x08	/* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xb4 0x08	/* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xb8 0x08	/* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xbc 0x08	/* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xc0 0x08	/* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xc4 0x08	/* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xc8 0x08	/* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xcc 0x08	/* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xd0 0x08	/* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xd4 0x08	/* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xd8 0x08	/* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xdc 0x08	/* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xe0 0x00	/* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+					0xe4 0x00	/* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+					0xe8 0x00	/* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+					0xec 0x00	/* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+				>;
+			};
+
+			bb_view_lcd_cape_keys_pins: pinmux_bb_view_lcd_cape_keys_pins {
+				pinctrl-single,pins = <
+					0x4C 0x27	/* gpmc_a3.gpio1_19,   INPUT | MODE7 */
+					0x184 0x27	/* uart1_txd.gpio0_15, INPUT | MODE7 */
+					0x44 0x27	/* gpmc_a1.gpio1_17,   INPUT | MODE7 */
+					0x70 0x27	/* gpmc_wait0.gpio0_30,INPUT | MODE7 */
+				>;
+			};
+
+		};
+	};
+
+	fragment@1 {
+		target = <&epwmss1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&ehrpwm1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&ocp>;
+
+		__overlay__ {
+
+			/* avoid stupid warning */
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			backlight {
+				compatible      = "pwm-backlight";
+ 				pinctrl-names   = "default";
+				pinctrl-0       = <&pwm_bl_pins>;
+
+				pwms = <&ehrpwm1 0 500000 0>;
+				pwm-names = "LCD4";
+				brightness-levels = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100>;
+				default-brightness-level = <101>; /* index to the array above */
+				status = "okay";
+ 			};
+
+			tscadc {
+				compatible = "ti,ti-tscadc";
+				reg = <0x44e0d000 0x1000>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <16>;
+				ti,hwmods = "adc_tsc";
+				status = "okay";
+
+				tsc {
+					ti,wires = <4>;
+					ti,x-plate-resistance = <200>;
+					ti,coordinate-readouts = <5>;
+					ti,touch-type = <1>;
+					ti,wire-config = <0x00 0x11 0x22 0x33>;
+				};
+
+				adc {
+					ti,adc-channels = <4 5 6 7>;
+				};
+			};
+
+			gpio-leds-cape-lcd {
+				compatible = "gpio-leds";
+				pinctrl-names = "default";
+
+				pinctrl-0 = <&bb_view_lcd_cape_led_pins>;
+
+				bb_view_led0 {
+					label = "bb-view:led0";
+					gpios = <&gpio2 28 0>;
+					linux,default-trigger = "none";
+					default-state = "off";
+				};
+
+/*
+				bb_view_led1 {
+					label = "bb-view:led1";
+					gpios = <&gpio1 12 0>;
+					linux,default-trigger = "none";
+					default-state = "off";
+				};
+*/
+			};
+
+			bb_view_gpio_keys {
+				compatible = "gpio-keys";
+				pinctrl-names = "default";
+				pinctrl-0 = <&bb_view_lcd_cape_keys_pins>;
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				button@1 {
+					debounce_interval = <50>;
+					label = "bb-view:usr0";
+					linux,code = <0x100>;
+					gpios = <&gpio2 19 0x0>;
+					gpio-key,wakeup;
+					autorepeat;
+				};
+				button@2 {
+					debounce_interval = <50>;
+					label = "bb-view:usr1";
+					linux,code = <0x101>;
+					gpios = <&gpio1 15 0x0>;
+					gpio-key,wakeup;
+					autorepeat;
+				};
+				button@3 {
+					debounce_interval = <50>;
+					label = "bb-view:usr2";
+					linux,code = <0x102>;
+					gpios = <&gpio2 17 0x0>;
+					gpio-key,wakeup;
+					autorepeat;
+				};
+				button@4 {
+					debounce_interval = <50>;
+					label = "bb-view:usr3";
+					linux,code = <0x103>;
+					gpios = <&gpio1 30 0x0>;
+					gpio-key,wakeup;
+					autorepeat;
+				};
+			};
+
+			/* Embest 4.3 inch LCD cape: */
+			panel {
+				compatible = "tilcdc,panel";
+				pinctrl-names = "default";
+				pinctrl-0 = <&bb_view_lcd_cape_pins>;
+				panel-info {
+					ac-bias           = <255>;
+					ac-bias-intrpt    = <0>;
+					dma-burst-sz      = <16>;
+					bpp               = <32>;
+					fdd               = <0x80>;
+					tft-alt-mode      = <0>;
+					stn-565-mode      = <0>;
+					mono-8bit-mode    = <0>;
+					sync-edge         = <0>;
+					sync-ctrl         = <1>;
+					raster-order      = <0>;
+					fifo-th           = <0>;
+				};
+				display-timings {
+					native-mode = <&timing0>;
+					timing0: 480x272 {
+						hactive         = <480>;
+						vactive         = <272>;
+						hback-porch     = <44>;
+						hfront-porch    = <9>;
+						hsync-len       = <5>;
+						vback-porch     = <13>;
+						vfront-porch    = <4>;
+						vsync-len       = <10>;
+						clock-frequency = <9000000>;
+						hsync-active    = <0>;
+						vsync-active    = <0>;
+					};
+				};
+			};
+
+			fb {
+				compatible = "ti,am33xx-tilcdc";
+				reg = <0x4830e000 0x1000>;
+				interrupt-parent = <&intc>;
+				interrupts = <36>;
+				bgrx_16bpp;
+				ti,hwmods = "lcdc";
+			};
+
+		};
+	};
+};
diff --git a/firmware/capes/BB-VIEW-LCD7-01-00A0.dts b/firmware/capes/BB-VIEW-LCD7-01-00A0.dts
new file mode 100644
index 0000000..47fa72f
--- /dev/null
+++ b/firmware/capes/BB-VIEW-LCD7-01-00A0.dts
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.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.
+ */
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "ti,beaglebone", "ti,beaglebone-black";
+
+	/* identification */
+	part-number = "BB-VIEW-LCD7-01";
+	version = "00A0";
+
+	/* state the resources this cape uses */
+	exclusive-use =
+		/* the pin header uses */
+		"P8.45",	/* lcd: lcd_data0 */
+		"P8.46",	/* lcd: lcd_data1 */
+		"P8.43",	/* lcd: lcd_data2 */
+		"P8.44",	/* lcd: lcd_data3 */
+		"P8.41",	/* lcd: lcd_data4 */
+		"P8.42",	/* lcd: lcd_data5 */
+		"P8.39",	/* lcd: lcd_data6 */
+		"P8.40",	/* lcd: lcd_data7 */
+		"P8.37",	/* lcd: lcd_data8 */
+		"P8.38",	/* lcd: lcd_data9 */
+		"P8.36",	/* lcd: lcd_data10 */
+		"P8.34",	/* lcd: lcd_data11 */
+		"P8.35",	/* lcd: lcd_data12 */
+		"P8.33",	/* lcd: lcd_data13 */
+		"P8.31",	/* lcd: lcd_data14 */
+		"P8.32",	/* lcd: lcd_data15 */
+		"P8.27",	/* lcd: lcd_vsync */
+		"P8.29",	/* lcd: lcd_hsync */
+		"P8.28",	/* lcd: lcd_pclk */
+		"P8.30",	/* lcd: lcd_ac_bias_en */
+		"P9.27",	/* lcd: gpio3_19 */
+		"P9.12",	/* led: gpio1_28 */
+		"P9.14",	/* pwm: ehrpwm1a */
+		"P9.15",	/* keys: gpio1_16 */
+		"P9.23",	/* keys: gpio1_17 */
+		"P9.16",	/* keys: gpio1_19 */
+		"P9.21",	/* keys: gpio0_3 */
+		/* the hardware IP uses */
+		"gpio3_19",
+		"gpio1_28",
+		"gpio1_16",
+		"gpio1_17",
+		"gpio1_19",
+		"gpio0_3",
+		/* "gpio0_12", */
+		"lcd",
+		"ehrpwm1a";
+
+	fragment@0 {
+		target = <&am33xx_pinmux>;
+		__overlay__ {
+
+			bb_view_lcd_cape_led_pins: pinmux_bb_view_lcd_cape_led_pins {
+				pinctrl-single,pins = <
+					0x078 0x2f      /* gpmc_be1n.gpio1_28, INPUT | PULLDIS | MODE7 */
+					/* 0x178 0x2f	 * uart1_ctsn.gpio0_12,INPUT | PULLDIS | MODE7 */
+				>;
+			};
+
+			pwm_bl_pins: pinmux_pwm_bl_pins {
+				pinctrl-single,pins = <
+					0x48 0x06       /* gpmc_a2.ehrpwm1a, OMAP_MUX_MODE6 | AM33XX_PIN_OUTPUT */
+				>;
+			};
+
+			bb_view_lcd_cape_pins: pinmux_bb_view_lcd_cape_pins {
+				pinctrl-single,pins = <
+					0xa0 0x08	/* lcd_data0.lcd_data0, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xa4 0x08	/* lcd_data1.lcd_data1, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xa8 0x08	/* lcd_data2.lcd_data2, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xac 0x08	/* lcd_data3.lcd_data3, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xb0 0x08	/* lcd_data4.lcd_data4, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xb4 0x08	/* lcd_data5.lcd_data5, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xb8 0x08	/* lcd_data6.lcd_data6, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xbc 0x08	/* lcd_data7.lcd_data7, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xc0 0x08	/* lcd_data8.lcd_data8, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xc4 0x08	/* lcd_data9.lcd_data9, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xc8 0x08	/* lcd_data10.lcd_data10, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xcc 0x08	/* lcd_data11.lcd_data11, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xd0 0x08	/* lcd_data12.lcd_data12, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xd4 0x08	/* lcd_data13.lcd_data13, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xd8 0x08	/* lcd_data14.lcd_data14, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xdc 0x08	/* lcd_data15.lcd_data15, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT | AM33XX_PULL_DISA */
+					0xe0 0x00	/* lcd_vsync.lcd_vsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+					0xe4 0x00	/* lcd_hsync.lcd_hsync, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+					0xe8 0x00	/* lcd_pclk.lcd_pclk, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+					0xec 0x00	/* lcd_ac_bias_en.lcd_ac_bias_en, OMAP_MUX_MODE0 | AM33XX_PIN_OUTPUT */
+				>;
+			};
+
+			bb_view_lcd_cape_keys_pins: pinmux_bb_view_lcd_cape_keys_pins {
+				pinctrl-single,pins = <
+					0x4C 0x27	/* gpmc_a3.gpio1_19,   INPUT | MODE7 */
+					0x184 0x27	/* uart1_txd.gpio0_15, INPUT | MODE7 */
+					0x44 0x27	/* gpmc_a1.gpio1_17,   INPUT | MODE7 */
+					0x70 0x27	/* gpmc_wait0.gpio0_30,INPUT | MODE7 */
+				>;
+			};
+
+		};
+	};
+
+	fragment@1 {
+		target = <&epwmss1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&ehrpwm1>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@3 {
+		target = <&ocp>;
+
+		__overlay__ {
+
+			/* avoid stupid warning */
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			backlight {
+				compatible      = "pwm-backlight";
+ 				pinctrl-names   = "default";
+				pinctrl-0       = <&pwm_bl_pins>;
+
+				pwms = <&ehrpwm1 0 500000 0>;
+				pwm-names = "LCD7";
+				brightness-levels = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100>;
+				default-brightness-level = <101>; /* index to the array above */
+				status = "okay";
+ 			};
+
+			tscadc {
+				compatible = "ti,ti-tscadc";
+				reg = <0x44e0d000 0x1000>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <16>;
+				ti,hwmods = "adc_tsc";
+				status = "okay";
+
+				tsc {
+					ti,wires = <4>;
+					ti,x-plate-resistance = <200>;
+					ti,coordinate-readouts = <5>;
+					ti,touch-type = <2>;
+					ti,wire-config = <0x00 0x11 0x22 0x33>;
+				};
+
+				adc {
+					ti,adc-channels = <4 5 6 7>;
+				};
+			};
+
+			gpio-leds-cape-lcd {
+				compatible = "gpio-leds";
+				pinctrl-names = "default";
+
+				pinctrl-0 = <&bb_view_lcd_cape_led_pins>;
+
+				bb_view_led0 {
+					label = "bb-view:led0";
+					gpios = <&gpio2 28 0>;
+					linux,default-trigger = "none";
+					default-state = "off";
+				};
+
+/*
+				bb_view_led1 {
+					label = "bb-view:led1";
+					gpios = <&gpio1 12 0>;
+					linux,default-trigger = "none";
+					default-state = "off";
+				};
+*/
+			};
+
+			bb_view_gpio_keys {
+				compatible = "gpio-keys";
+				pinctrl-names = "default";
+				pinctrl-0 = <&bb_view_lcd_cape_keys_pins>;
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				button@1 {
+					debounce_interval = <50>;
+					label = "bb-view:usr0";
+					linux,code = <0x100>;
+					gpios = <&gpio2 19 0x0>;
+					gpio-key,wakeup;
+					autorepeat;
+				};
+				button@2 {
+					debounce_interval = <50>;
+					label = "bb-view:usr1";
+					linux,code = <0x101>;
+					gpios = <&gpio1 15 0x0>;
+					gpio-key,wakeup;
+					autorepeat;
+				};
+				button@3 {
+					debounce_interval = <50>;
+					label = "bb-view:usr2";
+					linux,code = <0x102>;
+					gpios = <&gpio2 17 0x0>;
+					gpio-key,wakeup;
+					autorepeat;
+				};
+				button@4 {
+					debounce_interval = <50>;
+					label = "bb-view:usr3";
+					linux,code = <0x103>;
+					gpios = <&gpio1 30 0x0>;
+					gpio-key,wakeup;
+					autorepeat;
+				};
+			};
+
+			/* Embest 7 inch LCD cape: */
+			panel {
+				compatible = "tilcdc,panel";
+				pinctrl-names = "default";
+				pinctrl-0 = <&bb_view_lcd_cape_pins>;
+				panel-info {
+					ac-bias           = <255>;
+					ac-bias-intrpt    = <0>;
+					dma-burst-sz      = <16>;
+					bpp               = <32>;
+					fdd               = <0x80>;
+					tft-alt-mode      = <0>;
+					stn-565-mode      = <0>;
+					mono-8bit-mode    = <0>;
+					sync-edge         = <0>;
+					sync-ctrl         = <1>;
+					raster-order      = <0>;
+					fifo-th           = <0>;
+				};
+				display-timings {
+					native-mode = <&timing0>;
+					timing0: 800x480 {
+						hactive         = <800>;
+						vactive         = <480>;
+						hback-porch     = <40>;
+						hfront-porch    = <40>;
+						hsync-len       = <48>;
+						vback-porch     = <30>;
+						vfront-porch    = <13>;
+						vsync-len       = <3>;
+						clock-frequency = <30000000>;
+						hsync-active    = <0>;
+						vsync-active    = <0>;
+					};
+				};
+			};
+
+			fb {
+				compatible = "ti,am33xx-tilcdc";
+				reg = <0x4830e000 0x1000>;
+				interrupt-parent = <&intc>;
+				interrupts = <36>;
+				bgrx_16bpp;
+				ti,hwmods = "lcdc";
+			};
+
+		};
+	};
+};
commit e5e67e83bdecc4b9357ea873100520ff4cbb49c9
Author: B. Scott Michel <[email protected]>
Date:   Thu May 29 11:44:40 2014 -0700

    sitara_red_blue_swap_workaround
    
    Provide a reasonable workaround for the TI Sitara LCD red/blue swap
    erraturm at 24bpp:
    
    - The tilcdc LCD driver initializes its framebuffer to insert its
      own fb_ops functions, where the RGB-to-BGR swap is handlded. The
      code essentially duplicates the original DRM code with a couple
      of tweaks.
    
    - The tilcdc LCD driver queries the device tree for the panel-info's
      bpp property so that the frame buffer's requested BPP matches the
      panels. Previously, 16bpp was hardcoded into the framebuffer
      initialization.
    
    - The RGB-to-BGR swap is signaled via the LCD's device tree 'fb'
      node using the boolean 'bgrx_16bpp' or 'bgrx_24bpp' properties.
    
      -- bgrx_16bpp: At least one LCD cape "fixes" the erratum by
         swapping the signals on the cape. If 16bpp is ever used,
         red and blue will be reversed.
    
      -- bgrx_24bpp: The normal use case to swap blue and red at
         24bpp color depth, for LCD capes that don't swap signals.
    
    - drivers/video/console/fbcon.c: Ensure that the fb_check_var()
      function is called before fb_set_par(), i.e., the two functions
      are called as a pair, as is done in fb_set_var() [fbmem.c]
    
    - Patch the touchscreen driver to reduce jitter. Could not backport
      current TI source; this patch originates from Element14.
    
    - tilcdc documentation updated.

diff --git a/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
index fff10da..4d6823b 100644
--- a/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
+++ b/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
@@ -17,6 +17,11 @@ Optional properties:
    the lcd controller.
  - max-pixelclock: The maximum pixel clock that can be supported
    by the lcd controller in KHz.
+ - bgrx_16bpp: Swap blue and red to work around the TI Sitara
+   erratum -- some LCD capes for BeagleBone Black output BGR in
+   16bpp mode so that 24 and 32bpp modes output "correct" color.
+ - bgrx_24bpp: Swap blue and red to work around the TI Sitara
+   erratum (should normally be used)
 
 Example:
 
@@ -26,4 +31,6 @@ Example:
 		interrupt-parent = <&intc>;
 		interrupts = <36>;
 		ti,hwmods = "lcdc";
+		bgrx_24bpp;
+		bgrx_16bpp;
 	};
diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile
index deda656..45f59da 100644
--- a/drivers/gpu/drm/tilcdc/Makefile
+++ b/drivers/gpu/drm/tilcdc/Makefile
@@ -5,6 +5,7 @@ tilcdc-y := \
 	tilcdc_tfp410.o \
 	tilcdc_slave.o \
 	tilcdc_panel.o \
+	tilcdc_fbdev.o \
 	tilcdc_drv.o
 
 obj-$(CONFIG_DRM_TILCDC)	+= tilcdc.o
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 09ae498..78e9dc0 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -22,6 +22,7 @@
 #include "tilcdc_tfp410.h"
 #include "tilcdc_slave.h"
 #include "tilcdc_panel.h"
+#include "tilcdc_fbdev.h"
 
 #include "drm_fb_helper.h"
 
@@ -60,8 +61,10 @@ static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev,
 static void tilcdc_fb_output_poll_changed(struct drm_device *dev)
 {
 	struct tilcdc_drm_private *priv = dev->dev_private;
-	if (priv->fbdev)
-		drm_fbdev_cma_hotplug_event(priv->fbdev);
+	if (priv->fbdev) {
+	        struct drm_fbdev_cma *fbdev_cma = (struct drm_fbdev_cma *) priv->fbdev;
+		drm_fbdev_cma_hotplug_event(fbdev_cma);
+	}
 }
 
 static const struct drm_mode_config_funcs mode_config_funcs = {
@@ -164,11 +167,13 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
 {
 	struct platform_device *pdev = dev->platformdev;
 	struct device_node *node = pdev->dev.of_node;
+	struct device_node *panel_info_node;
 	struct tilcdc_drm_private *priv;
 	struct resource *res;
 	enum of_gpio_flags ofgpioflags;
 	unsigned long gpioflags;
 	int gpio, ret;
+	uint32_t preferred_bpp;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
@@ -268,8 +273,26 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
 	DBG("Allowing Non Audio Monitor Modes: %s",
 			priv->allow_non_audio ? "true" : "false");
 
+	priv->bgrx_16bpp_swap = of_property_read_bool(node, "bgrx_16bpp");
+
+	DBG("Enable 16bpp BGRx swap: %s",
+	                priv->bgrx_16bpp_swap ? "true" : "false");
+
+	priv->bgrx_24bpp_swap = of_property_read_bool(node, "bgrx_24bpp");
+
+	DBG("Enable 24bpp BGRx swap: %s",
+	                priv->bgrx_24bpp_swap ? "true" : "false");
+
 	pm_runtime_enable(dev->dev);
 
+	/* Query the preferred BPP from the DTS' panel-info/bpp property */
+	panel_info_node = of_find_node_by_path("/ocp/panel/panel-info");
+	if (!panel_info_node ||
+	    of_property_read_u32(panel_info_node, "bpp", &preferred_bpp))
+	        preferred_bpp = TILCDC_DEFAULT_PREFERRED_BPP;
+
+	DBG("preferred_bpp %d", preferred_bpp);
+
 	/* Determine LCD IP Version */
 	pm_runtime_get_sync(dev->dev);
 	switch (tilcdc_read(dev, LCDC_PID_REG)) {
@@ -312,7 +335,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
 
 	platform_set_drvdata(pdev, dev);
 
-	priv->fbdev = drm_fbdev_cma_init(dev, 16,
+	priv->fbdev = tilcdc_fbdev_cma_init(dev, preferred_bpp,
 			dev->mode_config.num_crtc,
 			dev->mode_config.num_connector);
 
@@ -335,7 +358,8 @@ static void tilcdc_preclose(struct drm_device *dev, struct drm_file *file)
 static void tilcdc_lastclose(struct drm_device *dev)
 {
 	struct tilcdc_drm_private *priv = dev->dev_private;
-	drm_fbdev_cma_restore_mode(priv->fbdev);
+	struct drm_fbdev_cma *fbdev_cma = (struct drm_fbdev_cma *) priv->fbdev;
+	drm_fbdev_cma_restore_mode(fbdev_cma);
 }
 
 static irqreturn_t tilcdc_irq(DRM_IRQ_ARGS)
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 7e0d640..7fd1455 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -31,6 +31,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
@@ -38,6 +39,9 @@
 #define TILCDC_DEFAULT_MAX_PIXELCLOCK  126000
 /* Defaulting to max width as defined on AM335x */
 #define TILCDC_DEFAULT_MAX_WIDTH  2048
+/* Default preferred BPP */
+#define TILCDC_DEFAULT_PREFERRED_BPP 16
+
 /*
  * This may need some tweaking, but want to allow at least 1280x1024@60
  * with optimized DDR & EMIF settings tweaked 1920x1080@25 appears to
@@ -64,6 +68,8 @@ struct tilcdc_drm_private {
 
 	int allow_non_rblank;	/* ATM we don't support non reduced blank modes */
 	int allow_non_audio;	/* allow modes that don't have working audio */
+        int bgrx_16bpp_swap;	/* 16bpp RBGx-to-BGRx workaround (Beagle LCD capes) */
+        int bgrx_24bpp_swap;    /* 24bpp RGBx-to-BGRx workaround (Beagle LCD capes) */
 
 	/* register contents saved across suspend/resume: */
 	u32 saved_register[12];
@@ -75,7 +81,7 @@ struct tilcdc_drm_private {
 
 	struct workqueue_struct *wq;
 
-	struct drm_fbdev_cma *fbdev;
+        struct tilcdc_drm_fbdev /* drm_fbdev_cma */ *fbdev;
 
 	struct drm_crtc *crtc;
 
@@ -84,6 +90,8 @@ struct tilcdc_drm_private {
 
 	unsigned int num_connectors;
 	struct drm_connector *connectors[8];
+
+        struct drm_fb_helper_funcs *drm_fb_helper_funcs;
 };
 
 /* Sub-module for display.  Since we don't know at compile time what panels
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_fbdev.c b/drivers/gpu/drm/tilcdc/tilcdc_fbdev.c
new file mode 100644
index 0000000..e0c89e9
--- /dev/null
+++ b/drivers/gpu/drm/tilcdc/tilcdc_fbdev.c
@@ -0,0 +1,315 @@
+/* tilcdc_fbdev.c
+ *
+ * Copyright (c) 2014 B. Scott Michel
+ * Author: B. Scott Michel ([email protected])
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * NOTE: This code provides the minimal DRM scaffolding copied from the
+ * drm_fb_cma_helper.c source needed to hook into struct fb_ops.fb_check_var
+ * function pointer.
+ */
+
+#include "tilcdc_drv.h"
+#include "tilcdc_fbdev.h"
+
+/*
+ * These structures were copied from the drm_fb_cma_helper.c source, they
+ * are bitwise equivalent:
+ * 
+ * tilcdc_fb_cma -> drm_fb_cma
+ * tilcdc_drm_fbdev -> drm_fbdev_cma
+ */
+struct tilcdc_fb_cma {
+	struct drm_framebuffer		fb;
+	struct drm_gem_cma_object	*obj[4];
+};
+
+struct tilcdc_drm_fbdev {
+	struct drm_fb_helper	drm_fb_helper;
+	struct tilcdc_fb_cma	*fb;
+};
+
+static inline struct tilcdc_drm_fbdev *to_tilcdc_fbdev(struct drm_fb_helper *helper)
+{
+	return container_of(helper, struct tilcdc_drm_fbdev, drm_fb_helper);
+}
+
+static inline struct tilcdc_fb_cma *to_tilcdc_fb_cma(struct drm_framebuffer *fb)
+{
+	return container_of(fb, struct tilcdc_fb_cma, fb);
+}
+
+static int tilcdc_fbdev_check_var(struct fb_var_screeninfo *var,
+				  struct fb_info *info)
+{
+	int ret, depth;
+	__u32 offs;
+	struct drm_fb_helper *helper = info->par;
+	struct drm_device *dev = helper->dev;
+	struct tilcdc_drm_private *priv = dev->dev_private;
+
+	ret = drm_fb_helper_check_var(var, info);
+	if (ret)
+		return ret;
+
+	/* Calculate current depth, prepare for RGBx->BGRx swap, if requested */
+	switch (var->bits_per_pixel) {
+	case 16:
+		depth = (var->green.length == 6) ? 16 : 15;
+		break;
+	case 32:
+		depth = (var->transp.length > 0) ? 32 : 24;
+		break;
+	default:
+		depth = var->bits_per_pixel;
+		break;
+	}
+
+	DBG("depth: %d", depth);
+
+	if ((depth == 16 && priv->bgrx_16bpp_swap) ||
+	    (depth == 24 && priv->bgrx_24bpp_swap)) {
+		/* RGBx -> BGRx reversal */
+		offs = var->red.offset;
+		var->red.offset = var->blue.offset;
+		var->blue.offset = offs;
+	}
+
+	return 0;
+}
+
+/* framebuffer operations adapted from drm_fb_cma_helper.c */
+static struct fb_ops tilcdc_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_fillrect	= sys_fillrect,
+	.fb_copyarea	= sys_copyarea,
+	.fb_imageblit	= sys_imageblit,
+	.fb_check_var	= tilcdc_fbdev_check_var,
+	.fb_set_par	= drm_fb_helper_set_par,
+	.fb_blank	= drm_fb_helper_blank,
+	.fb_pan_display	= drm_fb_helper_pan_display,
+	.fb_setcmap	= drm_fb_helper_setcmap,
+};
+
+static int tilcdc_fb_cma_create_handle(struct drm_framebuffer *fb,
+	struct drm_file *file_priv, unsigned int *handle)
+{
+	struct tilcdc_fb_cma *fb_cma = to_tilcdc_fb_cma(fb);
+
+	return drm_gem_handle_create(file_priv,
+			&fb_cma->obj[0]->base, handle);
+}
+
+static void tilcdc_fb_cma_destroy(struct drm_framebuffer *fb)
+{
+	struct tilcdc_fb_cma *fb_cma = to_tilcdc_fb_cma(fb);
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		if (fb_cma->obj[i])
+			drm_gem_object_unreference_unlocked(&fb_cma->obj[i]->base);
+	}
+
+	drm_framebuffer_cleanup(fb);
+	kfree(fb_cma);
+}
+
+static struct drm_framebuffer_funcs tilcdc_fb_cma_funcs = {
+	.destroy	= tilcdc_fb_cma_destroy,
+	.create_handle	= tilcdc_fb_cma_create_handle,
+};
+
+static struct drm_fb_helper_funcs tilcdc_fb_cma_helper_funcs = {
+	.fb_probe = tilcdc_drm_fbdev_probe,
+};
+
+/* Copied from drm_fb_cma_helper.c */
+static struct tilcdc_fb_cma *tilcdc_fb_cma_alloc(struct drm_device *dev,
+	struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj,
+	unsigned int num_planes)
+{
+	struct tilcdc_fb_cma *fb_cma;
+	int ret;
+	int i;
+
+	DBG("allocating fb_cma");
+
+	fb_cma = kzalloc(sizeof(*fb_cma), GFP_KERNEL);
+	if (!fb_cma)
+		return ERR_PTR(-ENOMEM);
+
+	ret = drm_framebuffer_init(dev, &fb_cma->fb, &tilcdc_fb_cma_funcs);
+	if (ret) {
+		dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret);
+		kfree(fb_cma);
+		return ERR_PTR(ret);
+	}
+
+	drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd);
+
+	for (i = 0; i < num_planes; i++)
+		fb_cma->obj[i] = obj[i];
+
+	return fb_cma;
+}
+
+static int tilcdc_drm_fbdev_create(struct drm_fb_helper *helper,
+				   struct drm_fb_helper_surface_size *sizes)
+{
+	struct tilcdc_drm_fbdev *fbdev_cma = to_tilcdc_fbdev(helper);
+	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+	struct drm_device *dev = helper->dev;
+	struct drm_gem_cma_object *obj;
+	struct drm_framebuffer *fb;
+	unsigned int bytes_per_pixel;
+	unsigned long offset;
+	struct fb_info *fbi;
+	size_t size;
+	int ret;
+
+	DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
+			sizes->surface_width, sizes->surface_height,
+			sizes->surface_bpp);
+
+	bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
+
+	mode_cmd.width = sizes->surface_width;
+	mode_cmd.height = sizes->surface_height;
+	mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+		sizes->surface_depth);
+
+	size = mode_cmd.pitches[0] * mode_cmd.height;
+	obj = drm_gem_cma_create(dev, size);
+	if (IS_ERR(obj))
+		return -ENOMEM;
+
+	fbi = framebuffer_alloc(0, dev->dev);
+	if (!fbi) {
+		dev_err(dev->dev, "Failed to allocate framebuffer info.\n");
+		ret = -ENOMEM;
+		goto err_drm_gem_cma_free_object;
+	}
+
+	fbi->par = helper;
+	fbi->flags = FBINFO_DEFAULT;
+	fbi->fbops = &tilcdc_fb_ops;
+
+	fbdev_cma->fb = tilcdc_fb_cma_alloc(dev, &mode_cmd, &obj, 1);
+	if (IS_ERR(fbdev_cma->fb)) {
+		dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
+		ret = PTR_ERR(fbdev_cma->fb);
+		goto err_framebuffer_release;
+	}
+
+	fb = &fbdev_cma->fb->fb;
+	helper->fb = fb;
+	helper->fbdev = fbi;
+
+	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+	if (ret) {
+		dev_err(dev->dev, "Failed to allocate color map.\n");
+		goto err_drm_fb_cma_destroy;
+	}
+
+	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
+	drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+
+	offset = fbi->var.xoffset * bytes_per_pixel;
+	offset += fbi->var.yoffset * fb->pitches[0];
+
+	dev->mode_config.fb_base = (resource_size_t)obj->paddr;
+	fbi->screen_base = obj->vaddr + offset;
+	fbi->fix.smem_start = (unsigned long)(obj->paddr + offset);
+	fbi->screen_size = size;
+	fbi->fix.smem_len = size;
+
+	return 0;
+
+err_drm_fb_cma_destroy:
+	tilcdc_fb_cma_destroy(fb);
+err_framebuffer_release:
+	framebuffer_release(fbi);
+err_drm_gem_cma_free_object:
+	drm_gem_cma_free_object(&obj->base);
+	return ret;
+}
+
+int tilcdc_drm_fbdev_probe(struct drm_fb_helper *helper,
+			   struct drm_fb_helper_surface_size *sizes)
+{
+	int ret = 0;
+
+	if (!helper->fb) {
+		ret = tilcdc_drm_fbdev_create(helper, sizes);
+		if (ret < 0) {
+			DRM_ERROR("failed to create fbdev.\n");
+			return ret;
+		}
+
+		ret = 1;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tilcdc_drm_fbdev_probe);
+
+struct tilcdc_drm_fbdev *tilcdc_fbdev_cma_init(struct drm_device *dev,
+	unsigned int preferred_bpp, unsigned int num_crtc,
+	unsigned int max_conn_count)
+{
+	struct tilcdc_drm_fbdev *fbdev_cma;
+	struct drm_fb_helper *helper;
+	int ret;
+
+	fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL);
+	if (!fbdev_cma) {
+		dev_err(dev->dev, "Failed to allocate drm fbdev.\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	fbdev_cma->drm_fb_helper.funcs = &tilcdc_fb_cma_helper_funcs;
+	helper = &fbdev_cma->drm_fb_helper;
+
+	ret = drm_fb_helper_init(dev, helper, num_crtc, max_conn_count);
+	if (ret < 0) {
+		dev_err(dev->dev, "Failed to initialize drm fb helper.\n");
+		goto err_free;
+	}
+
+	ret = drm_fb_helper_single_add_all_connectors(helper);
+	if (ret < 0) {
+		dev_err(dev->dev, "Failed to add connectors.\n");
+		goto err_drm_fb_helper_fini;
+
+	}
+
+	ret = drm_fb_helper_initial_config(helper, preferred_bpp);
+	if (ret < 0) {
+		dev_err(dev->dev, "Failed to set inital hw configuration.\n");
+		goto err_drm_fb_helper_fini;
+	}
+
+	return fbdev_cma;
+
+err_drm_fb_helper_fini:
+	drm_fb_helper_fini(helper);
+err_free:
+	kfree(fbdev_cma);
+
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(tilcdc_fbdev_cma_init);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_fbdev.h b/drivers/gpu/drm/tilcdc/tilcdc_fbdev.h
new file mode 100644
index 0000000..970299b
--- /dev/null
+++ b/drivers/gpu/drm/tilcdc/tilcdc_fbdev.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 B. Scott Michel
+ * Author: B. Scott Michel ([email protected])
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TILCDC_FBDEV_H__
+#define __TILCDC_FBDEV_H__
+
+struct tilcdc_fb_cma;
+struct tilcdc_drm_fbdev;
+
+int tilcdc_drm_fbdev_probe(struct drm_fb_helper *helper,
+			   struct drm_fb_helper_surface_size *sizes);
+
+struct tilcdc_drm_fbdev *tilcdc_fbdev_cma_init(struct drm_device *dev,
+	unsigned int preferred_bpp, unsigned int num_crtc,
+	unsigned int max_conn_count);
+
+#endif
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index ed83043..fe7f903 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -53,7 +53,10 @@ struct titsc {
 	u32			config_inp[4];
 	u32			bit_xp, bit_xn, bit_yp, bit_yn;
 	u32			inp_xp, inp_xn, inp_yp, inp_yn;
-	unsigned int 		prevZ;
+#define	TOUCH_TYPE_LCD_NORM	0
+#define	TOUCH_TYPE_LCD43	1
+#define	TOUCH_TYPE_LCD7		2
+	int			touch_type;
 };
 
 static unsigned int titsc_readl(struct titsc *ts, unsigned int reg)
@@ -61,6 +64,19 @@ static unsigned int titsc_readl(struct titsc *ts, unsigned int reg)
 	return readl(ts->mfd_tscadc->tscadc_base + reg);
 }
 
+static u32 reg_read(unsigned addr) { return readl((const volatile void*)addr); }
+static int dump_regs(char* name, unsigned addr, int size) {
+	int i;
+	u32 reg;
+
+	for (i = 0; i < size; i += sizeof(int)) {
+		reg = reg_read(addr + i);
+		printk("%s[%.4X] = 0x%.8X\n", name, i, reg);
+	}
+	return 0;
+}
+
+
 static void titsc_writel(struct titsc *tsc, unsigned int reg,
 					unsigned int val)
 {
@@ -176,15 +192,15 @@ static void titsc_step_config(struct titsc *ts_dev)
 	/* Charge step configuration */
 	config = ts_dev->bit_xp | ts_dev->bit_yn |
 			STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR |
-			STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp);
+			STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_xn);
 
 	titsc_writel(ts_dev, REG_CHARGECONFIG, config);
 	titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY);
 
 	/* coordinate_readouts * 2 … coordinate_readouts * 2 + 2 is for Z */
 	config = STEPCONFIG_MODE_HWSYNC |
-			STEPCONFIG_AVG_16 | ts_dev->bit_yp |
-			ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM |
+			STEPCONFIG_AVG_16 | STEPCONFIG_YPN |
+			STEPCONFIG_XNP | STEPCONFIG_INM_ADCREFM |
 			STEPCONFIG_INP(ts_dev->inp_xp);
 	titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
 	titsc_writel(ts_dev, REG_STEPDELAY(end_step),
@@ -205,10 +221,11 @@ static void titsc_read_coordinates(struct titsc *ts_dev,
 		u32 *x, u32 *y, u32 *z1, u32 *z2)
 {
 	unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
-	unsigned int read;
+	unsigned int prev_val_x = ~0, prev_val_y = ~0;
+	unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
+	unsigned int read, diff;
 	unsigned int i, channel;
 	unsigned int creads = ts_dev->coordinate_readouts;
-	unsigned int nX, nY;
 
 	*z1 = *z2 = 0;
 	if (fifocount % (creads * 2 + 2))
@@ -221,21 +238,27 @@ static void titsc_read_coordinates(struct titsc *ts_dev,
 	 * algorithm compares the difference with that of a present value,
 	 * if true the value is reported to the sub system.
 	 */
-	*x=0;
-	*y=0;
-	nX=0;
-	nY=0;
 	for (i = 0; i < fifocount; i++) {
 		read = titsc_readl(ts_dev, REG_FIFO0);
 
 		channel = (read & 0xf0000) >> 16;
 		read &= 0xfff;
 		if (channel < creads) {
-			(*x)+=read;
-			nX++;
+			diff = abs(read - prev_val_x);
+			if (diff < prev_diff_x) {
+				prev_diff_x = diff;
+				*x = read;
+			}
+			prev_val_x = read;
+
 		} else if (channel < creads * 2) {
-			(*y)+=read;
-			nY++;
+			diff = abs(read - prev_val_y);
+			if (diff < prev_diff_y) {
+				prev_diff_y = diff;
+				*y = read;
+			}
+			prev_val_y = read;
+
 		} else if (channel < creads * 2 + 1) {
 			*z1 = read;
 
@@ -243,12 +266,6 @@ static void titsc_read_coordinates(struct titsc *ts_dev,
 			*z2 = read;
 		}
 	}
-	if (nX != 0) {
-		(*x)/=nX;
-	}
-	if (nY != 0) {
-		(*y)/=nY;
-	}
 }
 
 static irqreturn_t titsc_irq(int irq, void *dev)
@@ -258,7 +275,6 @@ static irqreturn_t titsc_irq(int irq, void *dev)
 	unsigned int status, irqclr = 0;
 	unsigned int x = 0, y = 0;
 	unsigned int z1, z2, z;
-	int deltaZ;
 	unsigned int fsm;
 
 	status = titsc_readl(ts_dev, REG_IRQSTATUS);
@@ -289,15 +305,21 @@ static irqreturn_t titsc_irq(int irq, void *dev)
 			z /= z2;
 			z = (z + 2047) >> 12;
 
-			// calculate the deltaZ :
-			deltaZ= z - ts_dev->prevZ;
-			// save the last z calculated :
-			ts_dev->prevZ=z;
-			pr_debug("x %d y %d deltaZ %d\n", x, y, deltaZ);
-
-			if (z <= MAX_12BIT && deltaZ>=0  && deltaZ<=10 ) {
+			if (z <= MAX_12BIT) {
+				if (ts_dev->touch_type != TOUCH_TYPE_LCD_NORM) {
+					x &= ~0x0007;
+					y &= ~0x0007;
+				}
+				if (ts_dev->touch_type == TOUCH_TYPE_LCD7) {
+					input_report_abs(input_dev, ABS_X, 4096 - y);
+					input_report_abs(input_dev, ABS_Y, x - 256);
+				} else if (ts_dev->touch_type == TOUCH_TYPE_LCD43) {
+					input_report_abs(input_dev, ABS_X, 4096 - x);
+					input_report_abs(input_dev, ABS_Y, 3840 - y);
+				} else {
 				input_report_abs(input_dev, ABS_X, x);
 				input_report_abs(input_dev, ABS_Y, y);
+				}
 				input_report_abs(input_dev, ABS_PRESSURE, z);
 				input_report_key(input_dev, BTN_TOUCH, 1);
 				input_sync(input_dev);
@@ -372,6 +394,11 @@ static int titsc_parse_dt(struct ti_tscadc_dev *tscadc_dev,
 	if (err < 0)
 		return err;
 
+	err = of_property_read_u32(node, "ti,touch-type", &ts_dev->touch_type);
+	if (err < 0) {
+		ts_dev->touch_type = TOUCH_TYPE_LCD_NORM;
+	}
+
 	return of_property_read_u32_array(node, "ti,wire-config",
 			ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp));
 }
@@ -452,15 +479,14 @@ static int titsc_probe(struct platform_device *pdev)
 	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
 
-	/*init prev Z*/
-	ts_dev->prevZ=0;
-
 	/* register to the input system */
 	err = input_register_device(input_dev);
 	if (err)
 		goto err_free_irq;
 
 	platform_set_drvdata(pdev, ts_dev);
+
+	dump_regs("TSC", (unsigned)ts_dev->mfd_tscadc->tscadc_base, REG_FIFO0);
 	return 0;
 
 err_free_irq:
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 6e696e6..d91ad8b 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -785,8 +785,17 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
 		  the fb_release() method of oldinfo may attempt to
 		  restore the hardware state.  This will leave the
 		  newinfo in an undefined state. Thus, a call to
-		  fb_set_par() may be needed for the newinfo.
+		  fb_check_par() and fb_set_par() may be needed for the
+		  newinfo.
 		*/
+		if (newinfo->fbops->fb_check_var) {
+			ret = newinfo->fbops->fb_check_var(&newinfo->var, newinfo);
+			if (ret)
+				printk(KERN_ERR "con2fb_release_oldinfo: detected "
+				       "unhandled fb_check_var error, "
+				       "error code %d\n", ret);
+		}
+
 		if (newinfo->fbops->fb_set_par) {
 			ret = newinfo->fbops->fb_set_par(newinfo);
 
@@ -808,13 +817,25 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
 
 	ops->currcon = fg_console;
 
-	if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) {
-		ret = info->fbops->fb_set_par(info);
+	if (!(ops->flags & FBCON_FLAGS_INIT)) {
+		/* Ensure that fb_check_var and fb_set_var are called
+		   as a pair. */
+	        if (info->fbops->fb_check_var) {
+		        ret = info->fbops->fb_check_var(&info->var, info);
+			if (ret)
+			      printk(KERN_ERR "con2fb_init_display: detected "
+				      "unhandled fb_check_var error, "
+				      "error code %d\n", ret);
+		}
 
-		if (ret)
-			printk(KERN_ERR "con2fb_init_display: detected "
-				"unhandled fb_set_par error, "
-				"error code %d\n", ret);
+		if (info->fbops->fb_set_par) {
+			ret = info->fbops->fb_set_par(info);
+
+			if (ret)
+				printk(KERN_ERR "con2fb_init_display: detected "
+				       "unhandled fb_set_par error, "
+				       "error code %d\n", ret);
+		}
 	}
 
 	ops->flags |= FBCON_FLAGS_INIT;
@@ -1142,14 +1163,23 @@ static void fbcon_init(struct vc_data *vc, int init)
 	 * We need to do it in fbcon_init() to prevent screen corruption.
 	 */
 	if (CON_IS_VISIBLE(vc) && vc->vc_mode == KD_TEXT) {
-		if (info->fbops->fb_set_par &&
-		    !(ops->flags & FBCON_FLAGS_INIT)) {
-			ret = info->fbops->fb_set_par(info);
+		if (!(ops->flags & FBCON_FLAGS_INIT)) {
+		        if (info->fbops->fb_check_var) {
+			        ret = info->fbops->fb_check_var(&info->var, info);
+				if (ret)
+				      printk(KERN_ERR "fbcon_init: detected "
+					      "unhandled fb_check_var error, "
+					      "error code %d\n", ret);
+			}
 
-			if (ret)
-				printk(KERN_ERR "fbcon_init: detected "
-					"unhandled fb_set_par error, "
-					"error code %d\n", ret);
+			if (info->fbops->fb_set_par) {
+				ret = info->fbops->fb_set_par(info);
+
+				if (ret)
+					printk(KERN_ERR "fbcon_init: detected "
+					       "unhandled fb_set_par error, "
+					       "error code %d\n", ret);
+			}
 		}
 
 		ops->flags |= FBCON_FLAGS_INIT;

Reply via email to