WIP: fdt: Add serial port controlled by device tree
PATCH 1/1 WIP: fdt: Add serial port controlled by device tree
This adds a new console serial port which is implemented by the driver selected in the device tree. It works by redirecting to another driver. It might be useful while we don't have proper serial device model and the drivers that do exist don't understand the device tree.
This patch is provided to assist Hanumant <[email protected]>. A suitable fdt fragment might be something like:
aliases {
console = "/serial at 70006300";
};
serial at 70006300 {
compatible = "nvidia,tegra250-uart", "ns16550";
reg = <0x70006000 0x40>;
id = <0>;
reg-shift = <2>;
interrupts = < 68 >;
clock-frequency = <216000000>;
};--- common/fdt_decode.c | 214 ++++++++++++++++++++++++++++++++++++++++ drivers/serial/Makefile | 1 + drivers/serial/serial_fdt.c | 228 +++++++++++++++++++++++++++++++++++++++++++ include/fdtdec.h | 1 + include/serial_fdt.h | 36 +++++++ lib/fdtdec.c | 1 + 6 files changed, 481 insertions(+), 0 deletions(-) create mode 100644 common/fdt_decode.c create mode 100644 drivers/serial/serial_fdt.c create mode 100644 include/serial_fdt.h
common/fdt_decode.c new file +214 -0
@@ -0,0 +1,214 @@ +/* +* Copyright (c) 2011 The Chromium OS Authors. +* See file CREDITS for list of people who contributed to this +* project. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* 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, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, +* MA 02111-1307 USA +*/ + +#include <common.h> +#include <serial.h> +#include <libfdt.h> +#include <fdt_support.h> +#include <fdt_decode.h> + +/* +* Here are the type we know about. One day we might allow drivers to +* register. For now we just put them here. +*/ +static struct fdt_compat compat_types[] = { + {COMPAT_UNKNOWN ,"<none>" }, + {COMPAT_SPI_UART_SWITCH ,"spi-uart-select" }, + {COMPAT_SERIAL_NS16550 ,"ns16550" }, +}; + +/** +* Look in the FDT for an alias with the given name and return its node. +* +* @param blob FDT blob +* @param name alias name to look up +* @return node offset if found, or an error code < 0 otherwise +*/ +static int find_alias_node (const void *blob,const char *name) +{ +const char *path; +int alias_node; + + alias_node =fdt_path_offset (blob,"/aliases" ); +if (alias_node <0 ) +return alias_node; + path =fdt_getprop (blob, alias_node, name,NULL ); +if (!path) +return -FDT_ERR_NOTFOUND ; +return fdt_path_offset (blob, path); +} + +/** +* Look up an address property in a node and return it as an address. +* The property must hold exactly one address with no trailing data. +* This is only tested on 32-bit machines. +* +* @param blob FDT blob +* @param node node to examine +* @param prop_name name of property to find +* @return address, if found, or ADDR_T_NONE if not +*/ +static addr_t get_addr (const void *blob,int node,const char *prop_name) +{ +const addr_t *cell; +int len; + + cell =fdt_getprop (blob, node, prop_name, &len); +if (cell && len !=sizeof (addr_t)) +return addr_to_cpu (*cell); +return ADDR_T_NONE ; +} + +/** +* Look up a 32-bit integer property in a node and return it. The property +* must have@least 4 bytes of data. The value of the first cell is +* returned. +* +* @param blob FDT blob +* @param node node to examine +* @param prop_name name of property to find +* @param default_val default value to return if the property is not found +* @return integer value, if found, or default_val if not +*/ +static s32 get_int (const void *blob,int node,const char *prop_name, +s32 default_val) +{ +const s32 *cell; +int len; + + cell =fdt_getprop (blob, node, prop_name, &len); +if (cell && len >=sizeof (s32)) +return fdt32_to_cpu (cell[0 ]); +return default_val; +} + +/** +* Look up a phandle and follow it to its node. Then return the offset +* of that node. +* +* @param blob FDT blob +* @param node node to examine +* @param prop_name name of property to find +* @return node offset if found, -ve error code on error +*/ +static int lookup_phandle (const void *blob,int node,const char *prop_name) +{ +const u32 *phandle; +int lookup; + + phandle =fdt_getprop (blob, node, prop_name,NULL ); +if (!phandle) +return -FDT_ERR_NOTFOUND ; + + lookup =fdt_node_offset_by_phandle (blob,fdt32_to_cpu (*phandle)); +return lookup; +} + +/** +* Checks whether a node is enabled. +* This looks for a 'status' property. If this exists, then returns 1 if +* the status is 'ok' and 0 otherwise. If there is no status property, +* it returns the default value. +* +* @param blob FDT blob +* @param node node to examine +* @param default_val default value to return if no 'status' property exists +* @return integer value 0/1, if found, or default_val if not +*/ +static int get_is_enabled (const void *blob,int node,int default_val) +{ +const char *cell; + + cell =fdt_getprop (blob, node,"status" ,NULL ); +if (cell) +return 0 ==strcmp (cell,"ok" ); +return default_val; +} + +void fdt_decode_uart_calc_divisor (struct fdt_uart *uart) +{ +if (uart->multiplier && uart->baudrate) + uart->divisor = (uart->clock_freq + + (uart->baudrate * (uart->multiplier /2 ))) / + (uart->multiplier * uart->baudrate); +} + +int fdt_decode_uart_console (const void *blob,struct fdt_uart *uart, +int default_baudrate) +{ +int node; + + node =find_alias_node (blob,"console" ); +if (node <0 ) +return node; + uart->reg =get_addr (blob, node,"reg" ); + uart->id =get_int (blob, node,"id" ,0 ); + uart->reg_shift =get_int (blob, node,"reg_shift" ,2 ); + uart->baudrate =get_int (blob, node,"baudrate" , default_baudrate); + uart->clock_freq =get_int (blob, node,"clock-frequency" ,-1 ); + uart->multiplier =get_int (blob, node,"multiplier" ,16 ); + uart->divisor =get_int (blob, node,"divisor" ,-1 ); + uart->enabled =get_is_enabled (blob, node,1 ); + uart->interrupt =get_int (blob, node,"interrupts" ,-1 ); + uart->silent =get_int (blob, node,"silent" ,0 ); + uart->compat =fdt_decode_lookup (blob, node); + +/* Calculate divisor if required */ +if (uart->divisor ==-1 ) +fdt_decode_uart_calc_divisor (uart); +return 0 ; +} + +enum fdt_compat_id fdt_decode_lookup (const void *blob,int node) +{ +enum fdt_compat_id id; + +/* Search our drivers */ +for (id =COMPAT_UNKNOWN ; id <COMPAT_COUNT ; id++) +if (0 ==fdt_node_check_compatible (blob, node, + compat_types[id].name)) +return id; +return COMPAT_UNKNOWN ; +} + +int fdt_decode_get_spi_switch (const void *blob,struct fdt_spi_uart *config) +{ +int node, uart_node; +const u32 *gpio; + + node =fdt_node_offset_by_compatible (blob,0 , +"nvidia,spi-uart-switch" ); +if (node <0 ) +return node; + + uart_node =lookup_phandle (blob, node,"uart" ); +if (uart_node <0 ) +return uart_node; + config->port =get_int (blob, uart_node,"id" ,-1 ); +if (config->port ==-1 ) +return -FDT_ERR_NOTFOUND ; + config->gpio =-1 ; + config->regs = (NS16550_t )get_addr (blob, uart_node,"reg" ); + gpio =fdt_getprop (blob, node,"gpios" ,NULL ); +if (gpio) + config->gpio =fdt32_to_cpu (gpio[1 ]); +return 0 ; +}
drivers/serial/Makefile +1 -0
@@ -55,6 +55,7 @@ COBJS-$(CONFIG_S3C44B0_SERIAL) += serial_s3c44b0.o COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o COBJS-$(CONFIG_SANDBOX_SERIAL) += sandbox.o COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o +COBJS-$(CONFIG_OF_SERIAL) += serial_fdt.o ifndef CONFIG_SPL_BUILD COBJS-$(CONFIG_USB_TTY) += usbtty.o
drivers/serial/serial_fdt.c new file +228 -0
228 lines not on this page · raw message
include/fdtdec.h +1 -0
@@ -57,6 +57,7 @@ struct fdt_memory {*/ enum fdt_compat_id {COMPAT_UNKNOWN , +COMPAT_SERIAL_NS16550 ,COMPAT_COUNT , };
include/serial_fdt.h new file +36 -0
@@ -0,0 +1,36 @@ +/* +* Copyright (c) 2011 The Chromium OS Authors. +* See file CREDITS for list of people who contributed to this +* project. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 2 of +* the License, or (at your option) any later version. +* +* 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, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, +* MA 02111-1307 USA +*/ + + +/* +* Provides a serial port defined by an FDT. This makes calls to the +* driver selected by the FDT. +*/ + +/** +* Return a pointer to the serial console device before relocation. +*/ +struct serial_device *serial_fdt_get_console_f (void ); + +/** +* Return a pointer to the serial console device after relocation. +*/ +struct serial_device *serial_fdt_get_console_r (void );
lib/fdtdec.c +1 -0
@@ -33,6 +33,7 @@ DECLARE_GLOBAL_DATA_PTR;*/ #define COMPAT (id, name) namestatic const char *const compat_names[COMPAT_COUNT ] = { +COMPAT (SERIAL_NS16550 ,"ns16550" ), };/**
Signature · 1 line
1.7.7.3
PATCH 1/1 WIP: fdt: Add serial port controlled by device tree
common/fdt_decode.c
Quoted 4 lines · On Tuesday 21 February 2012 01:41:21 Simon Glass wrote:
common/fdt_decode.c new file +1
-0+static struct fdt_compat compat_types[] = {
const
common/fdt_decode.c line 152
Quoted 7 lines
common/fdt_decode.c new file +7
-0+void fdt_decode_uart_calc_divisor (struct fdt_uart *uart) +{ +if (uart->multiplier && uart->baudrate) + uart->divisor = (uart->clock_freq + + (uart->baudrate * (uart->multiplier /2 ))) / + (uart->multiplier * uart->baudrate); +}
does the multiplier really need to be part of device tree ?
common/fdt_decode.c line 198
Quoted 7 lines
+int
fdt_decode_get_spi_switch(const void *blob, struct fdt_spi_uart *config)+{common/fdt_decode.c new file +5
-0+int node, uart_node; +const u32 *gpio; + + node =fdt_node_offset_by_compatible (blob,0 , +"nvidia,spi-uart-switch" );
what's with the hardcoded SoC names in common code ?
drivers/serial/serial_fdt.c line 69
Quoted 10 lines
drivers/serial/serial_fdt.c new file +7
-0+void uart_calc_divisor (struct fdt_uart *uart) +{ +if (uart->multiplier && uart->baudrate) + uart->divisor = (uart->clock_freq + + (uart->baudrate * (uart->multiplier /2 ))) / + (uart->multiplier * uart->baudrate); +}
isn't this exactly the same as fdt_decode_uart_calc_divisor ?
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20120221/c3fec348/attachment.pgp>
PATCH 1/1 WIP: fdt: Add serial port controlled by device tree
Hi Mike,
Quoted 3 lines · Mike Frysinger
common/fdt_decode.c
Quoted 2 lines · On Tuesday 21 February 2012 01:41:21 Simon Glass wrote:
common/fdt_decode.c new file +0
-0
This whole file was not supposed to be there. I removed it from being needed but somehow not from the patch, sorry.
Quoted 28 lines
Quoted 2 lines
+static struct
fdt_compatcompat_types[] = {const
common/fdt_decode.c
Quoted 7 lines
common/fdt_decode.c new file +7
-0+void fdt_decode_uart_calc_divisor (struct fdt_uart *uart) +{ + ? ? if (uart->multiplier && uart->baudrate) + ? ? ? ? ? ? uart->divisor = (uart->clock_freq + + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (uart->baudrate * (uart->multiplier / 2))) / + ? ? ? ? ? ? ? ? ? ? (uart->multiplier * uart->baudrate); +}does the multiplier really need to be part of device tree ?
Quoted 7 lines
+int
fdt_decode_get_spi_switch(const void *blob, struct fdt_spi_uart *config)+{
+ ? ? int node,uart_node;
+ ? ? const u32 *gpio;
+
+ ? ? node = fdt_node_offset_by_compatible(blob, 0,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"nvidia,spi-uart-switch");what's with the hardcoded SoC names in common code ?
Quoted 3 lines
drivers/serial/serial_fdt.c new file +0
-0
Quoted 9 lines
drivers/serial/serial_fdt.c
Quoted 7 lines
drivers/serial/serial_fdt.c new file +7
-0+void uart_calc_divisor (struct fdt_uart *uart) +{ + ? ? if (uart->multiplier && uart->baudrate) + ? ? ? ? ? ? uart->divisor = (uart->clock_freq + + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (uart->baudrate * (uart->multiplier / 2))) / + ? ? ? ? ? ? ? ? ? ? (uart->multiplier * uart->baudrate); +}isn't this exactly the same as
fdt_decode_uart_calc_divisor?
Yes, I copied these functions out.
This patch was just for hanumant but I am going to create a proper version of this and will post to the list soon.
Quoted 1 line
-mike
Regards,
Simon