arm-sdk

os build toolkit for various embedded devices
git clone https://git.parazyd.org/arm-sdk
Log | Files | Refs | Submodules | README | LICENSE

0001-UPSTREAM-soc-rockchip-add-handler-for-usb-uart-funct.patch (9392B)


      1 From c0c863786b85a631e22eeae78f572d3f151af490 Mon Sep 17 00:00:00 2001
      2 From: Heiko Stuebner <heiko@sntech.de>
      3 Date: Mon, 25 May 2015 16:38:07 +0200
      4 Subject: [PATCH 3/4] UPSTREAM: soc/rockchip: add handler for usb-uart
      5  functionality
      6 
      7 Some Rockchip SoCs provide the possibility to use a usb-phy as passthru for
      8 the debug uart, making it possible to get console output without needing to
      9 open the device.
     10 
     11 This patch adds an early_initcall to enable this functionality conditionally
     12 and also disables the corresponding usb controller in the devicetree.
     13 
     14 Change-Id: I397df8f402c752125cf512332398757b91a899f8
     15 Signed-off-by: Alexandru M Stan <amstan@chromium.org>
     16 ---
     17  drivers/soc/Kconfig                      |   1 +
     18  drivers/soc/Makefile                     |   1 +
     19  drivers/soc/rockchip/Kconfig             |  13 ++
     20  drivers/soc/rockchip/Makefile            |   1 +
     21  drivers/soc/rockchip/rockchip_usb_uart.c | 223 +++++++++++++++++++++++++++++++
     22  5 files changed, 239 insertions(+)
     23  create mode 100644 drivers/soc/rockchip/Kconfig
     24  create mode 100644 drivers/soc/rockchip/Makefile
     25  create mode 100644 drivers/soc/rockchip/rockchip_usb_uart.c
     26 
     27 diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
     28 index 1ee0b57..ad2f71a 100644
     29 --- a/drivers/soc/Kconfig
     30 +++ b/drivers/soc/Kconfig
     31 @@ -2,6 +2,7 @@ menu "SOC (System On Chip) specific Drivers"
     32  
     33  source "drivers/soc/img/Kconfig"
     34  source "drivers/soc/qcom/Kconfig"
     35 +source "drivers/soc/rockchip/Kconfig"
     36  source "drivers/soc/tegra/Kconfig"
     37  
     38  endmenu
     39 diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
     40 index bc43b87..d80386c 100644
     41 --- a/drivers/soc/Makefile
     42 +++ b/drivers/soc/Makefile
     43 @@ -4,4 +4,5 @@
     44  
     45  obj-$(CONFIG_SOC_IMG)		+= img/
     46  obj-$(CONFIG_ARCH_QCOM)		+= qcom/
     47 +obj-$(CONFIG_ARCH_ROCKCHIP)    += rockchip/
     48  obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
     49 diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
     50 new file mode 100644
     51 index 0000000..24d4e05
     52 --- /dev/null
     53 +++ b/drivers/soc/rockchip/Kconfig
     54 @@ -0,0 +1,13 @@
     55 +#
     56 +# Rockchip Soc drivers
     57 +#
     58 +config ROCKCHIP_USB_UART
     59 +	bool "Rockchip usb-uart override"
     60 +	depends on ARCH_ROCKCHIP
     61 +	select MFD_SYSCON
     62 +	help
     63 +	  Say y here to enable usb-uart functionality. Newer Rockchip SoCs
     64 +	  provide means to repurpose one usb phy as uart2 output, making it
     65 +	  possible to get debug output without needing to open a device.
     66 +	  To enable this function on boot, add a rockchip.usb_uart option
     67 +	  to the kernel commandline.
     68 diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
     69 new file mode 100644
     70 index 0000000..b5dd6f8
     71 --- /dev/null
     72 +++ b/drivers/soc/rockchip/Makefile
     73 @@ -0,0 +1 @@
     74 +obj-$(CONFIG_ROCKCHIP_USB_UART)		+=	rockchip_usb_uart.o
     75 diff --git a/drivers/soc/rockchip/rockchip_usb_uart.c b/drivers/soc/rockchip/rockchip_usb_uart.c
     76 new file mode 100644
     77 index 0000000..97754f9
     78 --- /dev/null
     79 +++ b/drivers/soc/rockchip/rockchip_usb_uart.c
     80 @@ -0,0 +1,223 @@
     81 +/*
     82 + * Copyright (c) 2015 Heiko Stuebner <heiko@sntech.de>
     83 + *
     84 + * This program is free software; you can redistribute it and/or modify
     85 + * it under the terms of the GNU General Public License as published by
     86 + * the Free Software Foundation; either version 2 of the License, or
     87 + * (at your option) any later version.
     88 + *
     89 + * This program is distributed in the hope that it will be useful,
     90 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
     91 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     92 + * GNU General Public License for more details.
     93 + */
     94 +
     95 +#include <linux/kernel.h>
     96 +#include <linux/init.h>
     97 +#include <linux/errno.h>
     98 +#include <linux/mfd/syscon.h>
     99 +#include <linux/of_address.h>
    100 +#include <linux/of_platform.h>
    101 +#include <linux/regmap.h>
    102 +#include <linux/slab.h>
    103 +
    104 +#define HIWORD_UPDATE(val, mask) \
    105 +		((val) | (mask) << 16)
    106 +
    107 +struct rockchip_uart_data {
    108 +	const char *grf_compatible;
    109 +	const char *usb_compatible;
    110 +	phys_addr_t usb_phys_addr;
    111 +	int (*init_uart)(const struct rockchip_uart_data *data,
    112 +			 struct regmap *grf);
    113 +};
    114 +
    115 +static int enable_usb_uart = 0;
    116 +
    117 +#define RK3288_UOC0_CON0				0x320
    118 +#define RK3288_UOC0_CON0_COMMON_ON_N			BIT(0)
    119 +#define RK3288_UOC0_CON0_DISABLE			BIT(4)
    120 +
    121 +#define RK3288_UOC0_CON2				0x328
    122 +#define RK3288_UOC0_CON2_SOFT_CON_SEL			BIT(2)
    123 +
    124 +#define RK3288_UOC0_CON3				0x32c
    125 +#define RK3288_UOC0_CON3_UTMI_SUSPENDN			BIT(0)
    126 +#define RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING		(1 << 1)
    127 +#define RK3288_UOC0_CON3_UTMI_OPMODE_MASK		(3 << 1)
    128 +#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC	(1 << 3)
    129 +#define RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK		(3 << 3)
    130 +#define RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED		BIT(5)
    131 +#define RK3288_UOC0_CON3_BYPASSDMEN			BIT(6)
    132 +#define RK3288_UOC0_CON3_BYPASSSEL			BIT(7)
    133 +
    134 +/*
    135 + * Enable the bypass of uart2 data through the otg usb phy.
    136 + * Original description in the TRM.
    137 + * 1. Disable the OTG block by setting OTGDISABLE0 to 1’b1.
    138 + * 2. Disable the pull-up resistance on the D+ line by setting OPMODE0[1:0] to 2’b01.
    139 + * 3. To ensure that the XO, Bias, and PLL blocks are powered down in Suspend mode, set COMMONONN to 1’b1.
    140 + * 4. Place the USB PHY in Suspend mode by setting SUSPENDM0 to 1’b0.
    141 + * 5. Set BYPASSSEL0 to 1’b1.
    142 + * 6. To transmit data, controls BYPASSDMEN0, and BYPASSDMDATA0.
    143 + * To receive data, monitor FSVPLUS0.
    144 + *
    145 + * The actual code in the vendor kernel does some things differently.
    146 + */
    147 +static int __init rk3288_init_usb_uart(const struct rockchip_uart_data *data,
    148 +				       struct regmap *grf)
    149 +{
    150 +	u32 val;
    151 +	int ret;
    152 +
    153 +	pr_info("%s\n", __func__);
    154 +
    155 +	/*
    156 +	 * COMMON_ON and DISABLE settings are described in the TRM,
    157 +	 * but where not present in the original code.
    158 +	 */
    159 +	val = HIWORD_UPDATE(RK3288_UOC0_CON0_COMMON_ON_N
    160 +				| RK3288_UOC0_CON0_DISABLE,
    161 +			    RK3288_UOC0_CON0_COMMON_ON_N
    162 +				| RK3288_UOC0_CON0_DISABLE);
    163 +	ret = regmap_write(grf, RK3288_UOC0_CON0, val);
    164 +	if (ret)
    165 +		return ret;
    166 +
    167 +	// FIXME: this makes my system hang, for whatever reason
    168 +	val = HIWORD_UPDATE(RK3288_UOC0_CON2_SOFT_CON_SEL,
    169 +			    RK3288_UOC0_CON2_SOFT_CON_SEL);
    170 +	ret = regmap_write(grf, RK3288_UOC0_CON2, val);
    171 +	if (ret)
    172 +		return ret;
    173 +
    174 +	val = HIWORD_UPDATE(RK3288_UOC0_CON3_UTMI_OPMODE_NODRIVING
    175 +				| RK3288_UOC0_CON3_UTMI_XCVRSEELCT_FSTRANSC
    176 +				| RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED,
    177 +			    RK3288_UOC0_CON3_UTMI_SUSPENDN
    178 +			        | RK3288_UOC0_CON3_UTMI_OPMODE_MASK
    179 +			        | RK3288_UOC0_CON3_UTMI_XCVRSEELCT_MASK
    180 +			        | RK3288_UOC0_CON3_UTMI_TERMSEL_FULLSPEED);
    181 +	ret = regmap_write(grf, RK3288_UOC0_CON3, val);
    182 +	if (ret)
    183 +		return ret;
    184 +
    185 +	val = HIWORD_UPDATE(RK3288_UOC0_CON3_BYPASSSEL
    186 +				| RK3288_UOC0_CON3_BYPASSDMEN,
    187 +			    RK3288_UOC0_CON3_BYPASSSEL
    188 +				| RK3288_UOC0_CON3_BYPASSDMEN);
    189 +	ret = regmap_write(grf, RK3288_UOC0_CON3, val);
    190 +	if (ret)
    191 +		return ret;
    192 +
    193 +	return 0;
    194 +}
    195 +
    196 +const struct rockchip_uart_data rk3288_uart_data = {
    197 +	.grf_compatible = "rockchip,rk3288-grf",
    198 +	.usb_compatible = "rockchip,rk3288-usb",
    199 +	.usb_phys_addr = 0xff580000,
    200 +	.init_uart = rk3288_init_usb_uart,
    201 +};
    202 +
    203 +static const struct of_device_id rockchip_usb_uart_ids[] = {
    204 +	{ .compatible = "rockchip,rk3288", .data = &rk3288_uart_data },
    205 +	{ }
    206 +};
    207 +
    208 +/*
    209 + * Find the usb controller using the shared usb-uart-phy in the dts and
    210 + * disable it.
    211 + */
    212 +static int __init
    213 +rockchip_disable_usb_controller(const struct rockchip_uart_data *data)
    214 +{
    215 +	struct device_node *np;
    216 +
    217 +	for_each_compatible_node(np, NULL, data->usb_compatible) {
    218 +		struct property *new_status;
    219 +		struct resource res;
    220 +		int ret;
    221 +
    222 +		ret = of_address_to_resource(np, 0, &res);
    223 +		if (ret) {
    224 +			pr_err("%s: could not get address of usb controller %s\n",
    225 +			       __func__, np->full_name);
    226 +			continue;
    227 +		}
    228 +
    229 +		/* not the controller we're looking for */
    230 +		if (res.start != data->usb_phys_addr)
    231 +			continue;
    232 +
    233 +		pr_info("%s: disabling usb controller %s\n",
    234 +			 __func__, np->full_name);
    235 +
    236 +		new_status = kzalloc(sizeof(*new_status), GFP_KERNEL);
    237 +		if (!new_status)
    238 +			return -ENOMEM;
    239 +
    240 +		new_status->name = kstrdup("status", GFP_KERNEL);
    241 +		new_status->length = sizeof("disabled");
    242 +		new_status->value = kstrdup("disabled", GFP_KERNEL);
    243 +
    244 +		return of_update_property(np, new_status);
    245 +	}
    246 +
    247 +	return 0;
    248 +}
    249 +
    250 +static const struct of_device_id *rockchip_usb_uart_data_lookup(void)
    251 +{
    252 +	struct device_node *root;
    253 +	const struct of_device_id *id;
    254 +
    255 +	root = of_find_node_by_path("/");
    256 +	if (!root)
    257 +		return NULL;
    258 +
    259 +	id = of_match_node(rockchip_usb_uart_ids, root);
    260 +	of_node_put(root);
    261 +
    262 +	return id;
    263 +}
    264 +
    265 +static int __init rockchip_init_usb_uart(void)
    266 +{
    267 +	const struct of_device_id *match;
    268 +	const struct rockchip_uart_data *data;
    269 +	struct regmap *grf;
    270 +	int ret;
    271 +
    272 +	if (!enable_usb_uart)
    273 +		return 0;
    274 +
    275 +	match = rockchip_usb_uart_data_lookup();
    276 +	if (!match)
    277 +		return -ENOTSUPP;
    278 +
    279 +	pr_info("%s: using settings for %s\n", __func__, match->compatible);
    280 +	data = match->data;
    281 +
    282 +	grf = syscon_regmap_lookup_by_compatible(data->grf_compatible);
    283 +	if (IS_ERR(grf)) {
    284 +		pr_err("%s: could not find GRF syscon\n", __func__);
    285 +		return PTR_ERR(grf);
    286 +	}
    287 +
    288 +	ret = data->init_uart(data, grf);
    289 +	if (ret) {
    290 +		pr_err("%s: could not init usb_uart\n", __func__);
    291 +		return ret;
    292 +	}
    293 +
    294 +	return rockchip_disable_usb_controller(data);
    295 +}
    296 +early_initcall(rockchip_init_usb_uart);
    297 +
    298 +static int __init rockchip_usb_uart(char *buf)
    299 +{
    300 +	enable_usb_uart = true;
    301 +	return 0;
    302 +}
    303 +early_param("rockchip.usb_uart", rockchip_usb_uart);
    304 -- 
    305 2.4.4
    306