| /* |
| * 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 |
| */ |
| |
| |
| /* |
| * This file contains convenience functions for decoding useful and |
| * enlightening information from FDTs. It is intended to be used by device |
| * drivers and board-specific code within U-Boot. It aims to reduce the |
| * amount of FDT munging required within U-Boot itself, so that driver code |
| * changes to support FDT are minimized. |
| */ |
| |
| #ifdef CONFIG_SYS_NS16550 |
| #include <ns16550.h> |
| #endif |
| |
| #include <asm/arch/clock.h> |
| |
| /* A typedef for a physical address. We should move it to a generic place */ |
| #ifdef CONFIG_PHYS_64BIT |
| typedef u64 addr_t; |
| #define ADDR_T_NONE (-1ULL) |
| #define addr_to_cpu(reg) be64_to_cpu(reg) |
| #define size_to_cpu(reg) be64_to_cpu(reg) |
| #else |
| typedef u32 addr_t; |
| #define ADDR_T_NONE (-1U) |
| #define addr_to_cpu(reg) be32_to_cpu(reg) |
| #define size_to_cpu(reg) be32_to_cpu(reg) |
| #endif |
| |
| /* Information obtained about memory from the FDT */ |
| struct fdt_memory { |
| addr_t start; |
| addr_t end; |
| }; |
| |
| /** |
| * Compat types that we know about and for which we might have drivers. |
| * Each is named COMPAT_<dir>_<filename> where <dir> is the directory |
| * within drivers. |
| */ |
| enum fdt_compat_id { |
| COMPAT_UNKNOWN, |
| COMPAT_NVIDIA_SPI_UART_SWITCH, /* SPI / UART switch */ |
| COMPAT_SERIAL_NS16550, /* NS16550 UART */ |
| COMPAT_NVIDIA_TEGRA250_USB, /* Tegra 250 USB port */ |
| COMPAT_NVIDIA_TEGRA250_SDMMC, /* Tegra 250 SDMMC port */ |
| COMPAT_NVIDIA_TEGRA250_KBC, /* Tegra 250 Keyboard */ |
| COMPAT_NVIDIA_TEGRA250_I2C, /* Tegra 250 i2c */ |
| |
| COMPAT_COUNT, |
| }; |
| |
| /* Information obtained about a UART from the FDT */ |
| struct fdt_uart { |
| addr_t reg; /* address of registers in physical memory */ |
| int id; /* id or port number (numbered from 0, default -1) */ |
| int reg_shift; /* each register is (1 << reg_shift) apart */ |
| int baudrate; /* baud rate, will be gd->baudrate if not defined */ |
| int clock_freq; /* clock frequency, -1 if not provided */ |
| int multiplier; /* divisor multiplier, default 16 */ |
| int divisor; /* baud rate divisor, default calculated */ |
| int enabled; /* 1 to enable, 0 to disable */ |
| int interrupt; /* interrupt line */ |
| int silent; /* 1 for silent UART (supresses output by default) */ |
| int io_mapped; /* 1 for IO mapped UART, 0 for memory mapped UART */ |
| enum fdt_compat_id compat; /* our selected driver */ |
| }; |
| |
| #ifdef CONFIG_SYS_NS16550 |
| /* Information about the spi/uart switch */ |
| struct fdt_spi_uart { |
| int gpio; /* GPIO to control switch */ |
| NS16550_t regs; /* Address of UART affected */ |
| u32 port; /* Port number of UART affected */ |
| }; |
| #endif |
| |
| enum { |
| FDT_GPIO_NONE = 255, /* an invalid GPIO used to end our list */ |
| FDT_GPIO_MAX = 224, /* maximum value GPIO number on Tegra2 */ |
| |
| FDT_GPIO_OUTPUT = 1 << 0, /* set as output (else input) */ |
| FDT_GPIO_HIGH = 1 << 1, /* set output as high (else low) */ |
| FDT_GPIO_ACTIVE_LOW = 1 << 2, /* input is active low (else high) */ |
| }; |
| |
| /* This is the state of a GPIO pin. For now it only handles output pins */ |
| struct fdt_gpio_state { |
| u8 gpio; /* GPIO number, or FDT_GPIO_NONE if none */ |
| u8 flags; /* FDT_GPIO_... flags */ |
| }; |
| |
| /* This tells us whether a fdt_gpio_state record is valid or not */ |
| #define fdt_gpio_isvalid(x) ((x)->gpio != FDT_GPIO_NONE) |
| |
| #define FDT_LCD_TIMINGS 4 |
| |
| enum { |
| FDT_LCD_TIMING_REF_TO_SYNC, |
| FDT_LCD_TIMING_SYNC_WIDTH, |
| FDT_LCD_TIMING_BACK_PORCH, |
| FDT_LCD_TIMING_FRONT_PORCH, |
| |
| FDT_LCD_TIMING_COUNT, |
| }; |
| |
| enum lcd_cache_t { |
| FDT_LCD_CACHE_OFF = 0, |
| FDT_LCD_CACHE_WRITE_THROUGH = 1 << 0, |
| FDT_LCD_CACHE_WRITE_BACK = 1 << 1, |
| FDT_LCD_CACHE_FLUSH = 1 << 2, |
| FDT_LCD_CACHE_WRITE_BACK_FLUSH = FDT_LCD_CACHE_WRITE_BACK | |
| FDT_LCD_CACHE_FLUSH, |
| }; |
| |
| /* Information about the LCD */ |
| struct fdt_lcd { |
| addr_t reg; /* address of registers in physical memory */ |
| int width; /* width in pixels */ |
| int height; /* height in pixels */ |
| int bpp; /* number of bits per pixel */ |
| |
| /* |
| * log2 of number of bpp, in general, unless it bpp is 24 in which |
| * case this field holds 24 also! This is a U-Boot thing. |
| */ |
| int log2_bpp; |
| struct pwfm_ctlr *pwfm; /* PWM to use for backlight */ |
| struct disp_ctlr *disp; /* Display controller to use */ |
| addr_t frame_buffer; /* Address of frame buffer */ |
| unsigned pixel_clock; /* Pixel clock in Hz */ |
| int horiz_timing[FDT_LCD_TIMING_COUNT]; /* Horizontal timing */ |
| int vert_timing[FDT_LCD_TIMING_COUNT]; /* Vertical timing */ |
| enum lcd_cache_t cache_type; |
| |
| struct fdt_gpio_state backlight_en; /* GPIO for backlight enable */ |
| struct fdt_gpio_state lvds_shutdown; /* GPIO for lvds shutdown */ |
| struct fdt_gpio_state backlight_vdd; /* GPIO for backlight vdd */ |
| struct fdt_gpio_state panel_vdd; /* GPIO for panel vdd */ |
| /* |
| * Panel required timings |
| * Timing 1: delay between panel_vdd-rise and data-rise |
| * Timing 2: delay between data-rise and backlight_vdd-rise |
| * Timing 3: delay between backlight_vdd and pwm-rise |
| * Timing 4: delay between pwm-rise and backlight_en-rise |
| */ |
| int panel_timings[FDT_LCD_TIMINGS]; |
| }; |
| |
| /* Parameters we need for USB */ |
| enum { |
| PARAM_DIVN, /* PLL FEEDBACK DIVIDer */ |
| PARAM_DIVM, /* PLL INPUT DIVIDER */ |
| PARAM_DIVP, /* POST DIVIDER (2^N) */ |
| PARAM_CPCON, /* BASE PLLC CHARGE Pump setup ctrl */ |
| PARAM_LFCON, /* BASE PLLC LOOP FILter setup ctrl */ |
| PARAM_ENABLE_DELAY_COUNT, /* PLL-U Enable Delay Count */ |
| PARAM_STABLE_COUNT, /* PLL-U STABLE count */ |
| PARAM_ACTIVE_DELAY_COUNT, /* PLL-U Active delay count */ |
| PARAM_XTAL_FREQ_COUNT, /* PLL-U XTAL frequency count */ |
| PARAM_DEBOUNCE_A_TIME, /* 10MS DELAY for BIAS_DEBOUNCE_A */ |
| PARAM_BIAS_TIME, /* 20US DELAY AFter bias cell op */ |
| |
| PARAM_COUNT |
| }; |
| |
| /* Information about USB */ |
| struct fdt_usb { |
| struct usb_ctlr *reg; /* address of registers in physical memory */ |
| int params[PARAM_COUNT]; /* timing parameters */ |
| int host_mode; /* 1 if port has host mode, else 0 */ |
| int utmi; /* 1 if port has external tranceiver, else 0 */ |
| int enabled; /* 1 to enable, 0 to disable */ |
| enum periph_id periph_id;/* peripheral id */ |
| }; |
| |
| /* Information about an SDMMC port */ |
| struct fdt_sdmmc { |
| struct tegra2_mmc *reg; /* address of registers in physical memory */ |
| int width; /* port width in bits (normally 4) */ |
| int removable; /* 1 for removable device, 0 for fixed */ |
| int enabled; /* 1 to enable, 0 to disable */ |
| struct fdt_gpio_state cd_gpio; /* card detect GPIO */ |
| struct fdt_gpio_state wp_gpio; /* write protect GPIO */ |
| struct fdt_gpio_state power_gpio; /* power GPIO */ |
| enum periph_id periph_id; /* peripheral id */ |
| }; |
| |
| enum { |
| FDT_KBC_KEY_COUNT = 128, /* number of keys in each map */ |
| }; |
| |
| /* Information about keycode mappings */ |
| struct fdt_kbc { |
| u8 plain_keycode[FDT_KBC_KEY_COUNT]; |
| u8 shift_keycode[FDT_KBC_KEY_COUNT]; |
| u8 fn_keycode[FDT_KBC_KEY_COUNT]; |
| u8 ctrl_keycode[FDT_KBC_KEY_COUNT]; |
| }; |
| |
| /* Information about i2c controller */ |
| struct fdt_i2c { |
| struct i2c_ctlr *reg; |
| int pinmux; |
| u32 speed; |
| enum periph_id periph_id; |
| }; |
| |
| enum { |
| FDT_NAND_MAX_TRP_TREA, |
| FDT_NAND_TWB, |
| FDT_NAND_MAX_TCR_TAR_TRR, |
| FDT_NAND_TWHR, |
| FDT_NAND_MAX_TCS_TCH_TALS_TALH, |
| FDT_NAND_TWH, |
| FDT_NAND_TWP, |
| FDT_NAND_TRH, |
| FDT_NAND_TADL, |
| |
| FDT_NAND_TIMING_COUNT |
| }; |
| |
| /* Information about an attached NAND chip */ |
| struct fdt_nand { |
| struct nand_ctlr *reg; |
| int enabled; /* 1 to enable, 0 to disable */ |
| struct fdt_gpio_state wp_gpio; /* write-protect GPIO */ |
| int width; /* bit width, normally 8 */ |
| int tag_ecc_bytes; /* ECC bytes to be generated for tag bytes */ |
| int tag_bytes; /* Tag bytes in spare area */ |
| int data_ecc_bytes; /* ECC bytes for data area */ |
| int skipped_spare_bytes; |
| /* |
| * How many bytes in spare area: |
| * spare area = skipped bytes + ECC bytes of data area |
| * + tag bytes + ECC bytes of tag bytes |
| */ |
| int page_spare_bytes; |
| int page_data_bytes; /* Bytes in data area */ |
| int timing[FDT_NAND_TIMING_COUNT]; |
| }; |
| |
| /** |
| * Returns information from the FDT about the memory. |
| * |
| * @param blob FDT blob to use |
| * @param config structure to use to return information |
| */ |
| int fdt_decode_memory(const void *blob, struct fdt_memory *config); |
| |
| /** |
| * Return information from the FDT about the console UART. This looks for |
| * an alias node called 'console' which must point to a UART. It then reads |
| * out the following attributes: |
| * |
| * reg |
| * port |
| * clock-frequency |
| * reg-shift (default 2) |
| * baudrate (default 115200) |
| * multiplier (default 16) |
| * divisor (calculated by default) |
| * enabled (default 1) |
| * interrupts (returns first in interrupt list, -1 if none) |
| * silent (default 0) |
| * cache-type (default FDT_LCD_CACHE_WRITE_BACK_FLUSH) |
| * |
| * The divisor calculation is performed by calling |
| * fdt_decode_uart_calc_divisor() automatically once the information is |
| * available. Therefore callers should be able to simply use the ->divisor |
| * field as their baud rate divisor. |
| * |
| * @param blob FDT blob to use |
| * @param uart struct to use to return information |
| * @param default_baudrate Baud rate to use if none defined in FDT |
| * @return 0 on success, -ve on error, in which case uart is unchanged |
| */ |
| int fdt_decode_uart_console(const void *blob, struct fdt_uart *uart, |
| int default_baudrate); |
| |
| /** |
| * Calculate the divisor to use for the uart. This is done based on the |
| * formula (uart clock / (baudrate * multiplier). The divisor is updated |
| * in the uart structure ready for use. |
| * |
| * @param uart uart structure to examine and update |
| */ |
| void fdt_decode_uart_calc_divisor(struct fdt_uart *uart); |
| |
| /** |
| * Find the compat id for a node. This looks at the 'compat' property of |
| * the node and looks up the corresponding ftp_compat_id. This is used for |
| * determining which driver will implement the decide described by the node. |
| */ |
| enum fdt_compat_id fdt_decode_lookup(const void *blob, int node); |
| |
| /** |
| * Find the next node which is compatible with the given id. Pass in a node |
| * of 0 the first time. |
| * |
| * @param blob FDT blob to use |
| * @param node Node offset to start search after |
| * @param id Compatible ID to look for |
| * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more |
| */ |
| int fdt_decode_next_compatible(const void *blob, int node, |
| enum fdt_compat_id id); |
| |
| /** |
| * Find the next numbered alias for a peripheral. This is used to enumerate |
| * all the peripherals of a certain type. |
| * |
| * Do the first call with *upto = 0. Assuming /aliases/<name>0 exists then |
| * this function will return a pointer to the node the alias points to, and |
| * then update *upto to 1. Next time you call this function, the next node |
| * will be returned. |
| * |
| * All nodes returned will match the compatible ID, as it is assumed that |
| * all peripherals use the same driver. |
| * |
| * @param blob FDT blob to use |
| * @param name Root name of alias to search for |
| * @param id Compatible ID to look for |
| * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more |
| */ |
| int fdt_decode_next_alias(const void *blob, const char *name, |
| enum fdt_compat_id id, int *upto); |
| |
| #ifdef CONFIG_SYS_NS16550 |
| /** |
| * Returns information from the FDT about the SPI / UART switch on tegra |
| * platforms. |
| * |
| * @param blob FDT blob to use |
| * @param config structure to use to return information |
| * @returns 0 on success, -ve on error, in which case config is unchanged |
| */ |
| int fdt_decode_get_spi_switch(const void *blob, struct fdt_spi_uart *config); |
| #endif |
| |
| /** |
| * Decode a single GPIOs from an FDT. |
| * |
| * @param blob FDT blob to use |
| * @param node Node to look at |
| * @param prop_name Node property name |
| * @param gpio gpio elements to fill from FDT |
| * @return 0 if ok, -FDT_ERR_MISSING if the property is missing. |
| */ |
| int fdt_decode_gpio(const void *blob, int node, const char *prop_name, |
| struct fdt_gpio_state *gpio); |
| |
| /** |
| * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no |
| * terminating item. |
| * |
| * @param blob FDT blob to use |
| * @param node Node to look at |
| * @param prop_name Node property name |
| * @param gpio Array of gpio elements to fill from FDT. This will be |
| * untouched if either 0 or an error is returned |
| * @param max_count Maximum number of elements allowed |
| * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would |
| * be exceeded, or -FDT_ERR_MISSING if the property is missing. |
| */ |
| int fdt_decode_gpios(const void *blob, int node, const char *prop_name, |
| struct fdt_gpio_state *gpio, int max_count); |
| |
| /** |
| * Set up a GPIO pin according to the provided gpio. This sets it to either |
| * input or output. If an output, then the defined value is assigned. |
| * |
| * @param gpio GPIO to set up |
| */ |
| void fdt_setup_gpio(struct fdt_gpio_state *gpio); |
| |
| /** |
| * Set up GPIO pins according to the list provided. |
| * |
| * @param gpio_list List of GPIOs to set up |
| */ |
| void fdt_setup_gpios(struct fdt_gpio_state *gpio_list); |
| |
| /** |
| * Converts an FDT GPIO record into a number and returns it. |
| * |
| * @param gpio GPIO to check |
| * @return gpio number, or -1 if none or not valid |
| */ |
| int fdt_get_gpio_num(struct fdt_gpio_state *gpio); |
| |
| /** |
| * Returns information from the FDT about the LCD display. This function reads |
| * out the following attributes: |
| * |
| * reg physical address of display peripheral |
| * width width in pixels |
| * height height in pixels |
| * bits_per_pixel put in bpp |
| * log2_bpp log2 of bpp (so bpp = 2 ^ log2_bpp) |
| * pwfm PWFM to use |
| * display Display to use (SOC peripheral) |
| * frame-buffer Frame buffer address (can be omitted since U-Boot will |
| * normally set this) |
| * pixel_clock Pixel clock in Hz |
| * horiz_timing ref_to_sync, sync_width. back_porch, front_porch |
| * vert_timing ref_to_sync, sync_width. back_porch, front_porch |
| * backlight_en GPIO to control backlight_en signal |
| * lvds_shutdown GPIO to control lvds_shutdown signal |
| * backlight_vdd GPIO to control the vdd of backlight |
| * panel_vdd GPIO to control the vdd of panel |
| * panel_timings the required timings in the panel init sequence |
| * |
| * @param blob FDT blob to use |
| * @param config structure to use to return information |
| * @returns 0 on success, -ve on error, in which case config may or may not be |
| * unchanged. If the node is present but expected data is |
| * missing then this will generally return |
| * -FDT_ERR_MISSING. |
| */ |
| int fdt_decode_lcd(const void *blob, struct fdt_lcd *config); |
| |
| /** |
| * Returns information from the FDT about the USB port. This function reads |
| * out the following attributes: |
| * |
| * reg |
| * params |
| * host-mode |
| * utmi |
| * periph-id |
| * enabled |
| * |
| * The params are read out according to the supplied clock frequency. This is |
| * done by looking for a compatible 'nvidia,tegra250-usbparams' node with |
| * osc-frequency set to the given value. |
| * |
| * @param blob FDT blob to use |
| * @param node Node to read from |
| * @param osc_frequency_mhz Current oscillator frequency |
| * @param config structure to use to return information |
| * @returns 0 on success, -ve on error, in which case config may or may not be |
| * unchanged. If the node is present but expected data is |
| * missing then this will generally return |
| * -FDT_ERR_MISSING. |
| */ |
| int fdt_decode_usb(const void *blob, int node, unsigned osc_frequency_mhz, |
| struct fdt_usb *config); |
| |
| /** |
| * Returns information from the FDT about an SDMMC port. This function reads |
| * out the following attributes: |
| * |
| * reg |
| * width |
| * periph-id |
| * enabled |
| * |
| * @param blob FDT blob to use |
| * @param node Node to read from |
| * @param config structure to use to return information |
| * @returns 0 on success, -ve on error, in which case config may or may not be |
| * unchanged. If the node is present but expected data is |
| * missing then this will generally return |
| * -FDT_ERR_MISSING. |
| */ |
| int fdt_decode_sdmmc(const void *blob, int node, struct fdt_sdmmc *config); |
| |
| /** |
| * Look in the FDT for a config item with the given name and return its value |
| * as a string. |
| * |
| * @param blob FDT blob |
| * @param prop_name property name to look up |
| * @returns property string, NULL on error. |
| */ |
| char *fdt_decode_get_config_string(const void *blob, const char *prop_name); |
| |
| /** |
| * Look in the FDT for a config item with the given name and return its value |
| * as a 32-bit integer. The property must have at least 4 bytes of data. The |
| * value of the first cell is returned. |
| * |
| * @param blob FDT blob |
| * @param prop_name property name to look up |
| * @param default_val default value to return if the property is not found |
| * @return integer value, if found, or default_val if not |
| */ |
| int fdt_decode_get_config_int(const void *blob, const char *prop_name, |
| int default_val); |
| |
| /** |
| * Returns information from the FDT about an i2c controller. This function |
| * reads out the following attributes: |
| * |
| * reg |
| * pinmux |
| * speed |
| * periph-id |
| * |
| * @param blob FDT blob to use |
| * @param node Node to read from |
| * @param config structure to use to return information |
| * @returns 0 on success, -ve on error, in which case config may or may not be |
| * unchanged. If the node is present but expected data is |
| * missing then this will generally return |
| * -FDT_ERR_MISSING. |
| */ |
| int fdt_decode_i2c(const void *blob, int node, struct fdt_i2c *config); |
| |
| /** |
| * Returns information from the FDT about the keboard controller. This |
| * function reads out the following attributes: |
| * |
| * reg |
| * keycode-plain |
| * keycode-shift |
| * keycode-fn |
| * keycode-ctrl |
| * |
| * @param blob FDT blob to use |
| * @param node Node to read from |
| * @param config structure to use to return information |
| * @returns 0 on success, -ve on error, in which case config may or may not be |
| * unchanged. If the node is present but expected data is |
| * missing then this will generally return |
| * -FDT_ERR_MISSING. |
| */ |
| int fdt_decode_kbc(const void *blob, int node, struct fdt_kbc *config); |
| |
| /** |
| * Returns the model name of the device. This returns the /model property |
| * from the fdt. |
| * |
| * \return model name, or "<not defined>" if unknown |
| */ |
| const char *fdt_decode_get_model(const void *blob); |
| |
| /** |
| * Returns the machine architecture ID of the device. This is used by Linux |
| * to specify the machine that it is running on. We put it in the fdt so that |
| * it can easily be controlled from there. |
| * |
| * \return architecture number or -1 if not found |
| */ |
| int fdt_decode_get_machine_arch_id(const void *blob); |
| |
| /** |
| * Returns information from the FDT about the attached NAND chip. This |
| * function reads out the following attributes from the chip node: |
| * |
| * controller |
| * page-data-bytes |
| * tag-ecc-bytes |
| * tag-bytes |
| * data-ecc-bytes |
| * skipped-spare-bytes |
| * page-spare-bytes |
| * timing |
| * |
| * and these from the controller phandle: |
| * |
| * reg |
| * status |
| * wp-gpio (optional) |
| * width |
| * |
| * @param blob FDT blob to use |
| * @param node Node to read from |
| * @param config structure to use to return information |
| * @returns 0 on success, -ve on error, in which case config may or may not be |
| * unchanged. If the node is present but expected data is |
| * missing then this will generally return |
| * -FDT_ERR_MISSING. |
| */ |
| int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config); |
| |
| /** |
| * Look up a property in a node which contains a memory region address and |
| * size. Then return a pointer to this address. if the address is zero, it is |
| * allocated with malloc() instead. |
| * |
| * The property must hold one address with a length. 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 |
| * @param size returns size of region |
| * @return pointer to region, or NULL if property not found/malloc failed |
| */ |
| void *fdt_decode_alloc_region(const void *blob, int node, |
| const char *prop_name, size_t *size); |