From patchwork Fri Mar 6 15:36:33 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jyri Sarha X-Patchwork-Id: 5955941 Return-Path: X-Original-To: patchwork-linux-omap@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id C5E43BF440 for ; Fri, 6 Mar 2015 15:37:23 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 8D2E020396 for ; Fri, 6 Mar 2015 15:37:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 1905A2039C for ; Fri, 6 Mar 2015 15:37:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932185AbbCFPhR (ORCPT ); Fri, 6 Mar 2015 10:37:17 -0500 Received: from arroyo.ext.ti.com ([192.94.94.40]:35051 "EHLO arroyo.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932162AbbCFPhN (ORCPT ); Fri, 6 Mar 2015 10:37:13 -0500 Received: from dlelxv90.itg.ti.com ([172.17.2.17]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id t26Fax8J022051; Fri, 6 Mar 2015 09:36:59 -0600 Received: from DLEE71.ent.ti.com (dlee71.ent.ti.com [157.170.170.114]) by dlelxv90.itg.ti.com (8.14.3/8.13.8) with ESMTP id t26FawQq022954; Fri, 6 Mar 2015 09:36:58 -0600 Received: from dlep32.itg.ti.com (157.170.170.100) by DLEE71.ent.ti.com (157.170.170.114) with Microsoft SMTP Server id 14.3.224.2; Fri, 6 Mar 2015 09:36:58 -0600 Received: from imryr.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id t26Faf6f017163; Fri, 6 Mar 2015 09:36:56 -0600 From: Jyri Sarha To: , , , , , CC: , , , , Jyri Sarha Subject: [PATCH v2 5/7] drm/tilcdc: Add DRM_TILCDC_SLAVE_COMPAT for ti, tilcdc, slave binding support Date: Fri, 6 Mar 2015 17:36:33 +0200 Message-ID: <3eb5e1bb6ce2debbc8c4853664f02b7e8b7eb461.1425656120.git.jsarha@ti.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Adds a CONFIG_DRM_TILCDC_SLAVE_COMPAT module for "ti,tilcdc,slave" node conversion. The implementation is in tilcdc_slave_compat.c and it uses tilcdc_slave_compat.dts as a basis for creating a DTS overlay. The DTS overlay adds an external tda998x encoder to tilcdc that corresponds to the old tda998x based slave encoder. Signed-off-by: Jyri Sarha --- drivers/gpu/drm/tilcdc/Kconfig | 13 ++ drivers/gpu/drm/tilcdc/Makefile | 3 + drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 270 +++++++++++++++++++++++++ drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts | 72 +++++++ 4 files changed, 358 insertions(+) create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c create mode 100644 drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig index 8394a0b..7e1e72b 100644 --- a/drivers/gpu/drm/tilcdc/Kconfig +++ b/drivers/gpu/drm/tilcdc/Kconfig @@ -1,3 +1,15 @@ +config DRM_TILCDC_SLAVE_COMPAT + bool "Support device tree blobs using TI LCDC Slave binding" + depends on DRM_TILCDC + default y + select OF_RESOLVE + select OF_OVERLAY + help + Choose this option if you need a kernel that is compatible + with device tree blobs using the obsolete "ti,tilcdc,slave" + binding. If you find "ti,tilcdc,slave"-string from your DTB, + you probably need this. Otherwise you do not. + config DRM_TILCDC tristate "DRM Support for TI LCDC Display Controller" depends on DRM && OF && ARM && HAVE_DMA_ATTRS @@ -8,6 +20,7 @@ config DRM_TILCDC select VIDEOMODE_HELPERS select BACKLIGHT_CLASS_DEVICE select BACKLIGHT_LCD_SUPPORT + select DRM_TILCDC_INIT help Choose this option if you have an TI SoC with LCDC display controller, for example AM33xx in beagle-bone, DA8xx, or diff --git a/drivers/gpu/drm/tilcdc/Makefile b/drivers/gpu/drm/tilcdc/Makefile index e1f738b..deeca48 100644 --- a/drivers/gpu/drm/tilcdc/Makefile +++ b/drivers/gpu/drm/tilcdc/Makefile @@ -3,6 +3,9 @@ ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) ccflags-y += -Werror endif +obj-$(CONFIG_DRM_TILCDC_SLAVE_COMPAT) += tilcdc_slave_compat.o \ + tilcdc_slave_compat.dtb.o + tilcdc-y := \ tilcdc_crtc.o \ tilcdc_tfp410.o \ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c new file mode 100644 index 0000000..cc9572d --- /dev/null +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2015 Texas Instruments + * Author: Jyri Sarha + * + * 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. + * + */ + +/* + * To support the old "ti,tilcdc,slave" binding the binding has to be + * transformed to the new external encoder binding. + */ + +#include +#include +#include +#include +#include +#include + +struct kfree_table { + int total; + int num; + void **table; +}; + +static int __init kfree_table_init(struct kfree_table *kft) +{ + kft->total = 32; + kft->num = 0; + kft->table = kmalloc(kft->total * sizeof(*kft->table), + GFP_KERNEL); + if (!kft->table) + return -ENOMEM; + + return 0; +} + +static int __init kfree_table_add(struct kfree_table *kft, void *p) +{ + if (kft->num == kft->total) { + void **old = kft->table; + + kft->total *= 2; + kft->table = krealloc(old, kft->total * sizeof(*kft->table), + GFP_KERNEL); + if (!kft->table) { + kft->table = old; + kfree(p); + return -ENOMEM; + } + } + kft->table[kft->num++] = p; + return 0; +} + +static void __init kfree_table_free(struct kfree_table *kft) +{ + int i; + + for (i = 0; i < kft->num; i++) + kfree(kft->table[i]); + + kfree(kft->table); +} + +static +struct property * __init tilcdc_prop_dup(const struct property *prop, + struct kfree_table *kft) +{ + struct property *nprop; + + nprop = kzalloc(sizeof(*nprop), GFP_KERNEL); + if (!nprop || kfree_table_add(kft, nprop)) + return NULL; + + nprop->name = kstrdup(prop->name, GFP_KERNEL); + if (!nprop->name || kfree_table_add(kft, nprop->name)) + return NULL; + + nprop->value = kmemdup(prop->value, prop->length, GFP_KERNEL); + if (!nprop->value || kfree_table_add(kft, nprop->value)) + return NULL; + + nprop->length = prop->length; + + return nprop; +} + +static void __init tilcdc_copy_props(struct device_node *from, + struct device_node *to, + const char * const props[], + struct kfree_table *kft) +{ + struct property *prop; + int i; + + for (i = 0; props[i]; i++) { + prop = of_find_property(from, props[i], NULL); + if (!prop) + continue; + + prop = tilcdc_prop_dup(prop, kft); + if (!prop) + continue; + + prop->next = to->properties; + to->properties = prop; + } +} + +static int __init tilcdc_prop_str_update(struct property *prop, + const char *str, + struct kfree_table *kft) +{ + prop->value = kstrdup(str, GFP_KERNEL); + if (kfree_table_add(kft, prop->value) || !prop->value) + return -ENOMEM; + prop->length = strlen(str)+1; + return 0; +} + +static void __init tilcdc_node_disable(struct device_node *node) +{ + struct property *prop; + + prop = kzalloc(sizeof(*prop), GFP_KERNEL); + if (!prop) + return; + + prop->name = "status"; + prop->value = "disabled"; + prop->length = strlen((char *)prop->value)+1; + + of_update_property(node, prop); +} + +struct device_node * __init tilcdc_get_overlay(struct kfree_table *kft) +{ + extern uint8_t __dtb_tilcdc_slave_compat_begin[]; + extern uint8_t __dtb_tilcdc_slave_compat_end[]; + const int size = __dtb_tilcdc_slave_compat_end - + __dtb_tilcdc_slave_compat_begin; + static void *overlay_data; + struct device_node *overlay; + int ret; + + if (!size) { + pr_warn("%s: No overlay data\n", __func__); + return NULL; + } + + overlay_data = kmemdup(__dtb_tilcdc_slave_compat_begin, + size, GFP_KERNEL); + if (!overlay_data || kfree_table_add(kft, overlay_data)) + return NULL; + + of_fdt_unflatten_tree(overlay_data, &overlay); + if (!overlay) { + pr_warn("%s: Unfattening overlay tree failed\n", __func__); + return NULL; + } + + of_node_set_flag(overlay, OF_DETACHED); + ret = of_resolve_phandles(overlay); + if (ret) { + pr_err("%s: Failed to resolve phandles: %d\n", __func__, ret); + return NULL; + } + + return overlay; +} + +static const struct of_device_id tilcdc_slave_of_match[] __initconst = { + { .compatible = "ti,tilcdc,slave", }, + {}, +}; + +static const struct of_device_id tilcdc_of_match[] __initconst = { + { .compatible = "ti,am33xx-tilcdc", }, + {}, +}; + +static const struct of_device_id tilcdc_tda998x_of_match[] __initconst = { + { .compatible = "nxp,tda998x", }, + {}, +}; + +static const char * const tilcdc_slave_props[] __initconst = { + "pinctrl-names", + "pinctrl-0", + "pinctrl-1", + NULL +}; + +void __init tilcdc_convert_slave_node(void) +{ + struct device_node *slave = NULL, *lcdc = NULL; + struct device_node *i2c = NULL, *fragment = NULL; + struct device_node *overlay, *encoder; + struct property *prop; + /* For all memory needed for the overlay tree. This memory can + be freed after the overlay has been applied. */ + struct kfree_table kft; + int ret; + + if (kfree_table_init(&kft)) + goto out; + + lcdc = of_find_matching_node(NULL, tilcdc_of_match); + slave = of_find_matching_node(NULL, tilcdc_slave_of_match); + + if (!slave || !of_device_is_available(lcdc)) + goto out; + + i2c = of_parse_phandle(slave, "i2c", 0); + if (!i2c) { + pr_err("%s: Can't find i2c node trough phandle\n", __func__); + goto out; + } + + overlay = tilcdc_get_overlay(&kft); + if (!overlay) + goto out; + + encoder = of_find_matching_node(overlay, tilcdc_tda998x_of_match); + if (!encoder) { + pr_err("%s: Failed to find tda998x node\n", __func__); + goto out; + } + + tilcdc_copy_props(slave, encoder, tilcdc_slave_props, &kft); + + for_each_child_of_node(overlay, fragment) { + prop = of_find_property(fragment, "target-path", NULL); + if (!prop) + continue; + if (!strncmp("i2c", (char *)prop->value, prop->length)) + if (tilcdc_prop_str_update(prop, i2c->full_name, &kft)) + goto out; + if (!strncmp("lcdc", (char *)prop->value, prop->length)) + if (tilcdc_prop_str_update(prop, lcdc->full_name, &kft)) + goto out; + } + + tilcdc_node_disable(slave); + + ret = of_overlay_create(overlay); + if (ret) + pr_err("%s: Creating overlay failed: %d\n", __func__, ret); + else + pr_info("%s: ti,tilcdc,slave node successfully converted\n", + __func__); +out: + kfree_table_free(&kft); + of_node_put(i2c); + of_node_put(slave); + of_node_put(lcdc); + of_node_put(fragment); +} + +int __init tilcdc_slave_compat_init(void) +{ + tilcdc_convert_slave_node(); + return 0; +} + +subsys_initcall(tilcdc_slave_compat_init); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts new file mode 100644 index 0000000..693f8b0 --- /dev/null +++ b/drivers/gpu/drm/tilcdc/tilcdc_slave_compat.dts @@ -0,0 +1,72 @@ +/* + * DTS overlay for converting ti,tilcdc,slave binding to new binding. + * + * Copyright (C) 2015 Texas Instruments Inc. + * Author: Jyri Sarha + * + * 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. + */ + +/* + * target-path property values are simple tags that are replaced with + * correct values in tildcdc_slave_compat.c. Some properties are also + * copied over from the ti,tilcdc,slave node. + */ + +/dts-v1/; +/ { + fragment@0 { + target-path = "i2c"; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + tda19988 { + compatible = "nxp,tda998x"; + reg = <0x70>; + status = "okay"; + + port { + hdmi_0: endpoint@0 { + remote-endpoint = <&lcd_0>; + }; + }; + }; + }; + }; + + fragment@1 { + target-path = "lcdc"; + __overlay__ { + port { + lcd_0: endpoint@0 { + remote-endpoint = <&hdmi_0>; + }; + }; + }; + }; + + __local_fixups__ { + fragment@0 { + __overlay__ { + tda19988 { + port { + endpoint@0 { + remote-endpoint = <0>; + }; + }; + }; + }; + }; + fragment@1 { + __overlay__ { + port { + endpoint@0 { + remote-endpoint = <0>; + }; + }; + }; + }; + }; +};