diff --git a/arch/arm/boards/efika-mx-smartbook/board.c b/arch/arm/boards/efika-mx-smartbook/board.c index 4a38afd..f023d70 100644 --- a/arch/arm/boards/efika-mx-smartbook/board.c +++ b/arch/arm/boards/efika-mx-smartbook/board.c @@ -187,6 +187,7 @@ gpio_direction_output(GPIO_WIFI_RESET, 0); gpio_direction_output(GPIO_SMSC3317_RESET, 0); gpio_direction_output(GPIO_HUB_RESET, 0); + gpio_direction_output(GPIO_BACKLIGHT_POWER, 1); mdelay(10); @@ -241,8 +242,6 @@ defaultenv_append_directory(defaultenv_efikasb); - gpio_direction_output(GPIO_BACKLIGHT_POWER, 1); - for (i = 0; i < ARRAY_SIZE(leds); i++) led_gpio_register(&leds[i]); diff --git a/arch/arm/dts/imx51-genesi-efika-sb.dts b/arch/arm/dts/imx51-genesi-efika-sb.dts index 26829d1..78cb1b7 100644 --- a/arch/arm/dts/imx51-genesi-efika-sb.dts +++ b/arch/arm/dts/imx51-genesi-efika-sb.dts @@ -90,12 +90,34 @@ mux-ext-port = <3>; }; - backlight { + backlight: backlight { compatible = "pwm-backlight"; + enable-gpios = <&gpio4 12 GPIO_ACTIVE_LOW>; pwms = <&pwm1 0 78770>; - brightness-levels = <0 4 8 16 32 64 128 255>; - default-brightness-level = <6>; - }; + brightness-levels = <0 1 2 4 8 16 32 64 128 255>; + default-brightness-level = <9>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_backlight>; + }; + + panel { + compatible = "simple-panel"; + backlight = <&backlight>; + enable-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; + ddc-i2c-bus = <&i2c2>; + enable-delay = <200>; + + port { + panel_in: endpoint { + remote-endpoint = <&mtl017_out>; + }; + }; + }; + + lvds_reg: lvds_regulator { + compatible = "regulator-fixed"; + gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>; + }; }; &ssi1 { @@ -115,16 +137,17 @@ MX51_PAD_DI1_PIN12__GPIO3_1 0x80000000 /* WLAN switch */ MX51_PAD_EIM_A17__GPIO2_11 0x80000000 /* Bluetooth power */ MX51_PAD_EIM_A23__GPIO2_17 0x80000000 /* Audio amp enable, 1 = on */ - MX51_PAD_CSI1_D8__GPIO3_12 0x80000000 /* LVDS enable, 1 = on */ - MX51_PAD_GPIO1_2__GPIO1_2 0x80000000 /* Backlight PWM */ - MX51_PAD_CSI2_D19__GPIO4_12 0x80000000 /* Backlight power, 0 = on */ - MX51_PAD_DISPB2_SER_DIN__GPIO3_5 0x80000000 /* LVDS reset (1 = reset) */ - MX51_PAD_DISPB2_SER_CLK__GPIO3_7 0x80000000 /* LVDS power, 1 = on */ - MX51_PAD_CSI1_D9__GPIO3_13 0x80000000 /* LCD enable (1 = on */ MX51_PAD_NANDF_CS0__GPIO3_16 0x80000000 /* Camera power, 0 = on */ MX51_PAD_GPIO1_5__GPIO1_5 0x80000000 /* USB hub reset, 0 = reset */ MX51_PAD_EIM_D27__GPIO2_9 0x80000000 /* USB phy reset, 0 = reset */ MX51_PAD_CSPI1_RDY__GPIO4_26 0x80000000 /* Audio clk enable */ + MX51_PAD_CSI2_D19__GPIO4_12 0x80000000 /* Backlight power, 0 = on */ + >; + }; + + pinctrl_backlight: backlightgrp { + fsl,pins = < + MX51_PAD_GPIO1_2__PWM1_PWMO 0x80000000 /* Backlight PWM */ >; }; @@ -187,34 +210,32 @@ >; }; - pinctrl_ipu_disp1: ipudisp1grp { + pinctrl_ipu_disp2: ipudisp2grp { fsl,pins = < - MX51_PAD_DISP1_DAT0__DISP1_DAT0 0x5 - MX51_PAD_DISP1_DAT1__DISP1_DAT1 0x5 - MX51_PAD_DISP1_DAT2__DISP1_DAT2 0x5 - MX51_PAD_DISP1_DAT3__DISP1_DAT3 0x5 - MX51_PAD_DISP1_DAT4__DISP1_DAT4 0x5 - MX51_PAD_DISP1_DAT5__DISP1_DAT5 0x5 - MX51_PAD_DISP1_DAT6__DISP1_DAT6 0x5 - MX51_PAD_DISP1_DAT7__DISP1_DAT7 0x5 - MX51_PAD_DISP1_DAT8__DISP1_DAT8 0x5 - MX51_PAD_DISP1_DAT9__DISP1_DAT9 0x5 - MX51_PAD_DISP1_DAT10__DISP1_DAT10 0x5 - MX51_PAD_DISP1_DAT11__DISP1_DAT11 0x5 - MX51_PAD_DISP1_DAT12__DISP1_DAT12 0x5 - MX51_PAD_DISP1_DAT13__DISP1_DAT13 0x5 - MX51_PAD_DISP1_DAT14__DISP1_DAT14 0x5 - MX51_PAD_DISP1_DAT15__DISP1_DAT15 0x5 - MX51_PAD_DISP1_DAT16__DISP1_DAT16 0x5 - MX51_PAD_DISP1_DAT17__DISP1_DAT17 0x5 - MX51_PAD_DISP1_DAT18__DISP1_DAT18 0x5 - MX51_PAD_DISP1_DAT19__DISP1_DAT19 0x5 - MX51_PAD_DISP1_DAT20__DISP1_DAT20 0x5 - MX51_PAD_DISP1_DAT21__DISP1_DAT21 0x5 - MX51_PAD_DISP1_DAT22__DISP1_DAT22 0x5 - MX51_PAD_DISP1_DAT23__DISP1_DAT23 0x5 - MX51_PAD_DI1_PIN2__DI1_PIN2 0x5 - MX51_PAD_DI1_PIN3__DI1_PIN3 0x5 + MX51_PAD_DISP2_DAT0__DISP2_DAT0 0x5 + MX51_PAD_DISP2_DAT1__DISP2_DAT1 0x5 + MX51_PAD_DISP2_DAT2__DISP2_DAT2 0x5 + MX51_PAD_DISP2_DAT3__DISP2_DAT3 0x5 + MX51_PAD_DISP2_DAT4__DISP2_DAT4 0x5 + MX51_PAD_DISP2_DAT5__DISP2_DAT5 0x5 + MX51_PAD_DISP2_DAT6__DISP2_DAT6 0x5 + MX51_PAD_DISP2_DAT7__DISP2_DAT7 0x5 + MX51_PAD_DISP2_DAT8__DISP2_DAT8 0x5 + MX51_PAD_DISP2_DAT9__DISP2_DAT9 0x5 + MX51_PAD_DISP2_DAT10__DISP2_DAT10 0x5 + MX51_PAD_DISP2_DAT11__DISP2_DAT11 0x5 + MX51_PAD_DISP2_DAT12__DISP2_DAT12 0x5 + MX51_PAD_DISP2_DAT13__DISP2_DAT13 0x5 + MX51_PAD_DISP2_DAT14__DISP2_DAT14 0x5 + MX51_PAD_DISP2_DAT15__DISP2_DAT15 0x5 + MX51_PAD_DI2_PIN2__DI2_PIN2 0x5 /* hsync */ + MX51_PAD_DI2_PIN3__DI2_PIN3 0x5 /* vsync */ + MX51_PAD_DI2_DISP_CLK__DI2_DISP_CLK 0x5 + MX51_PAD_DI_GP4__DI2_PIN15 0x5 + MX51_PAD_CSI1_D8__GPIO3_12 0x80000000 /* LVDS enable, 1 = on */ + MX51_PAD_DISPB2_SER_DIN__GPIO3_5 0x80000000 /* LVDS reset (1 = reset) */ + MX51_PAD_DISPB2_SER_CLK__GPIO3_7 0x80000000 /* LVDS power, 1 = on */ + MX51_PAD_CSI1_D9__GPIO3_13 0x80000000 /* LCD enable (1 = on */ >; }; @@ -342,13 +363,38 @@ }; lvds: mtl017@3a { + #address-cells = <1>; + #size-cells = <0>; compatible = "mtl017"; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_ipu_disp1>; + pinctrl-0 = <&pinctrl_ipu_disp2>; + enable-gpios = <&gpio3 12 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>; + vdd-supply = <&lvds_reg>; reg = <0x3a>; - crtcs = <&ipu 1>; - edid-i2c = <&i2c2>; - interface-pix-fmt = "rgb565"; + + port@0 { + reg = <0>; + + mtl017_in: endpoint { + remote-endpoint = <&ipu_di1_disp1>; + }; + }; + + port@1 { + reg = <1>; + + mtl017_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + +&ipu_di1 { + interface-pix-fmt = "rgb565"; + endpoint { + remote-endpoint = <&mtl017_in>; }; }; @@ -371,7 +417,7 @@ partition@0 { label = "barebox-environment"; - reg = <0x80000 0x80000>; + reg = <0xc0000 0x40000>; }; }; diff --git a/drivers/of/base.c b/drivers/of/base.c index 7f35ee5..d12bfe3 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1570,6 +1571,23 @@ EXPORT_SYMBOL(of_get_next_available_child); /** + * of_get_next_child - Iterate a node childs + * @node: parent node + * @prev: previous child of the parent node, or NULL to get first + * + * Returns a node pointer with refcount incremented. + */ +struct device_node *of_get_next_child(const struct device_node *node, + struct device_node *prev) +{ + prev = list_prepare_entry(prev, &node->children, parent_list); + list_for_each_entry_continue(prev, &node->children, parent_list) + return prev; + return NULL; +} +EXPORT_SYMBOL(of_get_next_child); + +/** * of_get_child_count - Count child nodes of given parent node * @parent: parent node * @@ -2026,3 +2044,191 @@ return of_device_disable(node); } + +/** + * of_graph_parse_endpoint() - parse common endpoint node properties + * @node: pointer to endpoint device_node + * @endpoint: pointer to the OF endpoint data structure + * + * The caller should hold a reference to @node. + */ +int of_graph_parse_endpoint(const struct device_node *node, + struct of_endpoint *endpoint) +{ + struct device_node *port_node = of_get_parent(node); + + if (!port_node) + pr_warn("%s(): endpoint %s has no parent node\n", + __func__, node->full_name); + + memset(endpoint, 0, sizeof(*endpoint)); + + endpoint->local_node = node; + /* + * It doesn't matter whether the two calls below succeed. + * If they don't then the default value 0 is used. + */ + of_property_read_u32(port_node, "reg", &endpoint->port); + of_property_read_u32(node, "reg", &endpoint->id); + + return 0; +} +EXPORT_SYMBOL(of_graph_parse_endpoint); + +/** + * of_graph_get_port_by_id() - get the port matching a given id + * @parent: pointer to the parent device node + * @id: id of the port + * + * Return: A 'port' node pointer with refcount incremented. + */ +struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id) +{ + struct device_node *port; + + for_each_child_of_node(node, port) { + u32 port_id = 0; + + if (strncmp(port->name, "port", 4) != 0) + continue; + of_property_read_u32(port, "reg", &port_id); + if (id == port_id) + return port; + } + + return NULL; +} +EXPORT_SYMBOL(of_graph_get_port_by_id); + +/** + * of_graph_get_next_endpoint() - get next endpoint node + * @parent: pointer to the parent device node + * @prev: previous endpoint node, or NULL to get first + * + * Return: An 'endpoint' node pointer with refcount incremented. Refcount + * of the passed @prev node is decremented. + */ +struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *endpoint; + struct device_node *port; + + if (!parent) + return NULL; + + /* + * Start by locating the port node. If no previous endpoint is specified + * search for the first port node, otherwise get the previous endpoint + * parent port node. + */ + if (!prev) { + struct device_node *node; + + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + port = of_get_child_by_name(parent, "port"); + if (!port) { + pr_err("%s(): no port node found in %s\n", + __func__, parent->full_name); + return NULL; + } + } else { + port = of_get_parent(prev); + if (!port) { + pr_warn("%s(): endpoint %s has no parent node\n", + __func__, prev->full_name); + return NULL; + } + } + + while (1) { + /* + * Now that we have a port node, get the next endpoint by + * getting the next child. If the previous endpoint is NULL this + * will return the first child. + */ + endpoint = of_get_next_child(port, prev); + if (endpoint) + return endpoint; + + /* No more endpoints under this port, try the next one. */ + prev = NULL; + + do { + port = of_get_next_child(parent, port); + if (!port) + return NULL; + } while (of_node_cmp(port->name, "port")); + } +} +EXPORT_SYMBOL(of_graph_get_next_endpoint); + +/** + * of_graph_get_remote_port_parent() - get remote port's parent node + * @node: pointer to a local endpoint device_node + * + * Return: Remote device node associated with remote endpoint node linked + * to @node. + */ +struct device_node *of_graph_get_remote_port_parent( + const struct device_node *node) +{ + struct device_node *np; + unsigned int depth; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && np; depth--) { + np = np->parent; + if (depth == 2 && of_node_cmp(np->name, "ports")) + break; + } + return np; +} +EXPORT_SYMBOL(of_graph_get_remote_port_parent); + +/** + * of_graph_get_remote_port() - get remote port node + * @node: pointer to a local endpoint device_node + * + * Return: Remote port node associated with remote endpoint node linked + * to @node. + */ +struct device_node *of_graph_get_remote_port(const struct device_node *node) +{ + struct device_node *np; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) + return NULL; + return np->parent; +} +EXPORT_SYMBOL(of_graph_get_remote_port); + +int of_graph_port_is_available(struct device_node *node) +{ + struct device_node *endpoint; + int available = 0; + + for_each_child_of_node(node, endpoint) { + struct device_node *remote_parent; + + remote_parent = of_graph_get_remote_port_parent(endpoint); + if (!remote_parent) + continue; + + if (!of_device_is_available(remote_parent)) + continue; + + available = 1; + } + + return available; +} +EXPORT_SYMBOL(of_graph_port_is_available); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 85ba91d..d7f5b07 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -11,6 +11,9 @@ select FONTS prompt "framebuffer console support" +config VIDEO_VPL + bool + config DRIVER_VIDEO_ATMEL bool "Atmel LCDC framebuffer driver" depends on ARCH_AT91 @@ -111,4 +114,22 @@ help Enable this to get support for backlight devices driven by a PWM. +comment "Video encoder chips" + +config DRIVER_VIDEO_MTL017 + bool "MTL017 LVDS encoder" + select VIDEO_VPL + help + The MTL017 is a parallel to lvds video encoder chip found on the + Efika MX Smartbook. + +config DRIVER_VIDEO_SIMPLE_PANEL + bool "Simple panel support" + select VIDEO_VPL + help + This enabled support for simple panels, i.e. panels which consist of + a mode definition and enable gpios in the devicetree. Unlike the + Linux Kernel implementation this one is able to understand display-timings + nodes so that it's not necessary to keep a list of all known displays + with their corresponding timings in barebox. endif diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 359135e..57e4864 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -4,6 +4,9 @@ obj-$(CONFIG_DRIVER_VIDEO_BACKLIGHT) += backlight.o obj-$(CONFIG_DRIVER_VIDEO_BACKLIGHT_PWM) += backlight-pwm.o obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbconsole.o +obj-$(CONFIG_VIDEO_VPL) += vpl.o +obj-$(CONFIG_DRIVER_VIDEO_MTL017) += mtl017.o +obj-$(CONFIG_DRIVER_VIDEO_SIMPLE_PANEL) += simple-panel.o obj-$(CONFIG_DRIVER_VIDEO_ATMEL) += atmel_lcdfb.o atmel_lcdfb_core.o obj-$(CONFIG_DRIVER_VIDEO_ATMEL_HLCD) += atmel_hlcdfb.o atmel_lcdfb_core.o diff --git a/drivers/video/imx-ipu-v3/Kconfig b/drivers/video/imx-ipu-v3/Kconfig index 2ca9132..386ff5b 100644 --- a/drivers/video/imx-ipu-v3/Kconfig +++ b/drivers/video/imx-ipu-v3/Kconfig @@ -1,6 +1,7 @@ config DRIVER_VIDEO_IMX_IPUV3 bool "i.MX IPUv3 driver" depends on ARCH_IMX + select VIDEO_VPL help Support the IPUv3 found on Freescale i.MX51/53/6 SoCs diff --git a/drivers/video/imx-ipu-v3/imx-hdmi.c b/drivers/video/imx-ipu-v3/imx-hdmi.c index e01bfe8..f5a2e3c 100644 --- a/drivers/video/imx-ipu-v3/imx-hdmi.c +++ b/drivers/video/imx-ipu-v3/imx-hdmi.c @@ -23,6 +23,7 @@ #include #include #include +#include