From patchwork Thu Sep 24 09:15:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Chou X-Patchwork-Id: 522198 X-Patchwork-Delegate: thomas@wytron.com.tw Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 23C1D1401AD for ; Thu, 24 Sep 2015 19:15:25 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 8B4294B8CA; Thu, 24 Sep 2015 11:15:22 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id V5vCgREcoCcL; Thu, 24 Sep 2015 11:15:22 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 29B9E4B86F; Thu, 24 Sep 2015 11:15:22 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 998714B86F for ; Thu, 24 Sep 2015 11:15:17 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 4RdQk68syZvM for ; Thu, 24 Sep 2015 11:15:17 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from www.wytron.com.tw (220-134-43-68.HINET-IP.hinet.net [220.134.43.68]) by theia.denx.de (Postfix) with ESMTP id 69D2C4B830 for ; Thu, 24 Sep 2015 11:15:12 +0200 (CEST) Received: from localhost.localdomain (unknown [192.168.1.250]) by www.wytron.com.tw (Postfix) with ESMTP id 9C917D00327; Thu, 24 Sep 2015 17:15:09 +0800 (CST) From: Thomas Chou To: u-boot@lists.denx.de Date: Thu, 24 Sep 2015 17:15:05 +0800 Message-Id: <1443086105-11783-1-git-send-email-thomas@wytron.com.tw> X-Mailer: git-send-email 2.1.4 Cc: Marek Vasut , clsee@altera.com, lftan@altera.com Subject: [U-Boot] [PATCH] nios2 : convert altera_pio to driver model X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Convert altera_pio to driver model. Signed-off-by: Thomas Chou --- arch/nios2/dts/3c120_devboard.dts | 38 ++++ arch/nios2/include/asm/gpio.h | 80 +------- board/altera/nios2-generic/nios2-generic.c | 7 - configs/nios2-generic_defconfig | 2 + drivers/gpio/Kconfig | 7 + drivers/gpio/altera_pio.c | 316 +++++++---------------------- include/configs/nios2-generic.h | 20 -- 7 files changed, 124 insertions(+), 346 deletions(-) diff --git a/arch/nios2/dts/3c120_devboard.dts b/arch/nios2/dts/3c120_devboard.dts index a35f5fe..f6ac273 100644 --- a/arch/nios2/dts/3c120_devboard.dts +++ b/arch/nios2/dts/3c120_devboard.dts @@ -132,6 +132,44 @@ clock-frequency = <62500000>; u-boot,dm-pre-reloc; }; + + user_led_pio_8out: gpio@0x4cc0 { + compatible = "altr,pio-1.0"; + reg = <0x00004cc0 0x00000010>; + resetvalue = <255>; + width = <8>; + #gpio-cells = <2>; + gpio-controller; + gpio-bank-name = "led"; + }; + + user_dipsw_pio_8in: gpio@0x4ce0 { + compatible = "altr,pio-1.0"; + reg = <0x00004ce0 0x00000010>; + interrupt-parent = <&cpu>; + interrupts = <8>; + edge_type = <2>; + level_trigger = <0>; + resetvalue = <0>; + width = <8>; + #gpio-cells = <2>; + gpio-controller; + gpio-bank-name = "dipsw"; + }; + + user_pb_pio_4in: gpio@0x4d00 { + compatible = "altr,pio-1.0"; + reg = <0x00004d00 0x00000010>; + interrupt-parent = <&cpu>; + interrupts = <9>; + edge_type = <2>; + level_trigger = <0>; + resetvalue = <0>; + width = <4>; + #gpio-cells = <2>; + gpio-controller; + gpio-bank-name = "pb"; + }; }; cfi_flash_64m: flash@0x0 { diff --git a/arch/nios2/include/asm/gpio.h b/arch/nios2/include/asm/gpio.h index 908381f..306ab4c 100644 --- a/arch/nios2/include/asm/gpio.h +++ b/arch/nios2/include/asm/gpio.h @@ -1,79 +1 @@ -/* - * nios2 gpio driver - * - * This gpio core is described in http://nioswiki.com/GPIO - * bit[0] data - * bit[1] output enable - * - * When CONFIG_SYS_GPIO_BASE is not defined, the board may either - * provide its own driver or the altera_pio driver may be used. - * - * Copyright (C) 2010 Thomas Chou - * - * 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. - */ - -#ifndef _ASM_NIOS2_GPIO_H_ -#define _ASM_NIOS2_GPIO_H_ - -#ifdef CONFIG_SYS_GPIO_BASE -#include - -static inline int gpio_request(unsigned gpio, const char *label) -{ - return 0; -} - -static inline int gpio_free(unsigned gpio) -{ - return 0; -} - -static inline int gpio_direction_input(unsigned gpio) -{ - writel(1, CONFIG_SYS_GPIO_BASE + (gpio << 2)); - return 0; -} - -static inline int gpio_direction_output(unsigned gpio, int value) -{ - writel(value ? 3 : 2, CONFIG_SYS_GPIO_BASE + (gpio << 2)); - return 0; -} - -static inline int gpio_get_value(unsigned gpio) -{ - return readl(CONFIG_SYS_GPIO_BASE + (gpio << 2)); -} - -static inline void gpio_set_value(unsigned gpio, int value) -{ - writel(value ? 3 : 2, CONFIG_SYS_GPIO_BASE + (gpio << 2)); -} - -static inline int gpio_is_valid(int number) -{ - return ((unsigned)number) < CONFIG_SYS_GPIO_WIDTH; -} -#else -#ifdef CONFIG_ALTERA_PIO -extern int altera_pio_init(u32 base, u8 width, char iot, - u32 rstval, u32 negmask, - const char *label); - -extern void altera_pio_info(void); -#define gpio_status() altera_pio_info() -#endif - -extern int gpio_request(unsigned gpio, const char *label); -extern int gpio_free(unsigned gpio); -extern int gpio_direction_input(unsigned gpio); -extern int gpio_direction_output(unsigned gpio, int value); -extern int gpio_get_value(unsigned gpio); -extern void gpio_set_value(unsigned gpio, int value); -extern int gpio_is_valid(int number); -#endif /* CONFIG_SYS_GPIO_BASE */ - -#endif /* _ASM_NIOS2_GPIO_H_ */ +#include diff --git a/board/altera/nios2-generic/nios2-generic.c b/board/altera/nios2-generic/nios2-generic.c index 384fee9..61d32c7 100644 --- a/board/altera/nios2-generic/nios2-generic.c +++ b/board/altera/nios2-generic/nios2-generic.c @@ -37,13 +37,6 @@ int board_early_init_f(void) int board_early_init_r(void) { -#ifdef CONFIG_ALTERA_PIO -#ifdef LED_PIO_BASE - altera_pio_init(LED_PIO_BASE, LED_PIO_WIDTH, 'o', - LED_PIO_RSTVAL, (1 << LED_PIO_WIDTH) - 1, - "led"); -#endif -#endif return 0; } diff --git a/configs/nios2-generic_defconfig b/configs/nios2-generic_defconfig index 9dc6a72..ad72272 100644 --- a/configs/nios2-generic_defconfig +++ b/configs/nios2-generic_defconfig @@ -1,5 +1,6 @@ CONFIG_NIOS2=y CONFIG_DM_SERIAL=y +CONFIG_DM_GPIO=y CONFIG_TARGET_NIOS2_GENERIC=y CONFIG_DEFAULT_DEVICE_TREE="3c120_devboard" CONFIG_HUSH_PARSER=y @@ -15,5 +16,6 @@ CONFIG_CMD_PING=y CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_DM=y +CONFIG_ALTERA_PIO=y CONFIG_ALTERA_JTAG_UART=y CONFIG_ALTERA_JTAG_UART_BYPASS=y diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ef57a89..9e49471 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -14,6 +14,13 @@ config DM_GPIO particular GPIOs that they provide. The uclass interface is defined in include/asm-generic/gpio.h. +config ALTERA_PIO + bool "Altera PIO driver" + depends on DM_GPIO + help + Select this to enable PIO for Altera devices. Please find + details on the "Embedded Peripherals IP User Guide" of Altera. + config DWAPB_GPIO bool "DWAPB GPIO driver" depends on DM && DM_GPIO diff --git a/drivers/gpio/altera_pio.c b/drivers/gpio/altera_pio.c index 3ca5907..14a922b 100644 --- a/drivers/gpio/altera_pio.c +++ b/drivers/gpio/altera_pio.c @@ -1,286 +1,122 @@ /* - * Driver for Altera's PIO ip core - * + * Copyright (C) 2015 Thomas Chou * Copyright (C) 2011 Missing Link Electronics * Joachim Foerster * * SPDX-License-Identifier: GPL-2.0+ - * - * To use this driver, in your board's config. header: - * #define CONFIG_ALTERA_PIO - * #define CONFIG_SYS_ALTERA_PIO_NUM - * #define CONFIG_SYS_ALTERA_PIO_GPIO_NUM - * And in your board's early setup routine: - * altera_pio_init(, , 'i'|'o'|'t', - * , , "label"); - * - 'i'|'o'|'t': PIO is input-only/output-only/tri-state - * - : for correct initial status display, output-only - * - is meant to be used to in cases of active-low - * GPIOs, such as LEDs and buttons (on/pressed == 0). Each bit - * which is 1 in inverts the corresponding GPIO's value - * before set/after get. So: gpio_set_value(gpio, 1) => LED on . - * - * Do NOT define CONFIG_SYS_GPIO_BASE ! - * - * Optionally, in your board's config. header: - * - To force a GPIO numbering scheme like in Linux ... - * #define CONFIG_GPIO_DOWNTO_NUMBERING - * ... starting with 255 (default) - * #define CONFIG_GPIO_DOWNTO_MAX 255 */ #include +#include +#include +#include +#include #include #include -#ifdef CONFIG_GPIO_DOWNTO_NUMBERING -#ifndef CONFIG_GPIO_DOWNTO_MAX -#define CONFIG_GPIO_DOWNTO_MAX 255 -#endif -#endif - -#define ALTERA_PIO_DATA 0x0 -#define ALTERA_PIO_DIR 0x4 - -#define GPIO_LABEL_SIZE 9 +DECLARE_GLOBAL_DATA_PTR; +struct altera_pio_regs { + u32 data; /* Data register */ + u32 direction; /* Direction register */ +}; -static struct altera_pio { - u32 base; - u8 width; - char iot; - u32 negmask; - u32 sh_data; - u32 sh_dir; - int gidx; - char label[GPIO_LABEL_SIZE]; -} pios[CONFIG_SYS_ALTERA_PIO_NUM]; +struct altera_pio_platdata { + struct altera_pio_regs *regs; + int gpio_count; + const char *bank_name; +}; -static int pio_num; - -static struct altera_pio_gpio { - unsigned num; - struct altera_pio *pio; - char reqlabel[GPIO_LABEL_SIZE]; -} gpios[CONFIG_SYS_ALTERA_PIO_GPIO_NUM]; - -static int pio_gpio_num; - - -static int altera_pio_gidx(unsigned gpio) +static int altera_pio_direction_input(struct udevice *dev, unsigned pin) { - int i; + struct altera_pio_platdata *plat = dev_get_platdata(dev); + struct altera_pio_regs *const regs = plat->regs; - for (i = 0; i < pio_gpio_num; ++i) { - if (gpio == gpios[i].num) - break; - } - if (i >= pio_gpio_num) - return -1; - return i; -} + clrbits_le32(®s->direction, 1 << pin); -static struct altera_pio *altera_pio_get_and_mask(unsigned gpio, u32 *mask) -{ - int gidx = altera_pio_gidx(gpio); - if (gidx < 0) - return NULL; - if (mask) - *mask = 1 << (gidx - gpios[gidx].pio->gidx); - return gpios[gidx].pio; + return 0; } -#define altera_pio_use_gidx(_gidx, _reqlabel) \ - { strncpy(gpios[_gidx].reqlabel, _reqlabel, GPIO_LABEL_SIZE); } -#define altera_pio_unuse_gidx(_gidx) { gpios[_gidx].reqlabel[0] = '\0'; } -#define altera_pio_is_gidx_used(_gidx) (gpios[_gidx].reqlabel[0] != '\0') - -static int altera_pio_gpio_init(struct altera_pio *pio, u8 width) +static int altera_pio_direction_output(struct udevice *dev, unsigned pin, + int val) { - u8 gidx = pio_gpio_num; - int i; - - if (!width) - return -1; - if ((pio_gpio_num + width) > CONFIG_SYS_ALTERA_PIO_GPIO_NUM) - return -1; - - for (i = 0; i < width; ++i) { -#ifdef CONFIG_GPIO_DOWNTO_NUMBERING - gpios[pio_gpio_num + i].num = \ - CONFIG_GPIO_DOWNTO_MAX + 1 - gidx - width + i; -#else - gpios[pio_gpio_num + i].num = pio_gpio_num + i; -#endif - gpios[pio_gpio_num + i].pio = pio; - altera_pio_unuse_gidx(pio_gpio_num + i); - } - pio_gpio_num += width; - return gidx; -} + struct altera_pio_platdata *plat = dev_get_platdata(dev); + struct altera_pio_regs *const regs = plat->regs; -int altera_pio_init(u32 base, u8 width, char iot, u32 rstval, u32 negmask, - const char *label) -{ - if (pio_num >= CONFIG_SYS_ALTERA_PIO_NUM) - return -1; + if (val) + setbits_le32(®s->data, 1 << pin); + else + clrbits_le32(®s->data, 1 << pin); + /* change the data first, then the direction. to avoid glitch */ + setbits_le32(®s->direction, 1 << pin); - pios[pio_num].base = base; - pios[pio_num].width = width; - pios[pio_num].iot = iot; - switch (iot) { - case 'i': - /* input only */ - pios[pio_num].sh_dir = 0; - pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA); - break; - case 'o': - /* output only */ - pios[pio_num].sh_dir = 0xffffffff & ((1 << width) - 1); - pios[pio_num].sh_data = rstval; - break; - case 't': - /* bidir, tri-state */ - pios[pio_num].sh_dir = readl(base + ALTERA_PIO_DIR); - pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA); - break; - default: - return -1; - } - pios[pio_num].negmask = negmask & ((1 << width) - 1); - pios[pio_num].gidx = altera_pio_gpio_init(&pios[pio_num], width); - if (pios[pio_num].gidx < 0) - return -1; - strncpy(pios[pio_num].label, label, GPIO_LABEL_SIZE); - return pio_num++; + return 0; } -void altera_pio_info(void) +static int altera_pio_get_value(struct udevice *dev, unsigned pin) { - int i; - int j; - int gidx; - u32 mask; + struct altera_pio_platdata *plat = dev_get_platdata(dev); + struct altera_pio_regs *const regs = plat->regs; - for (i = 0; i < pio_num; ++i) { - printf("Altera PIO % 2d, @0x%08x, " - "width: %u, label: %s\n", - i, pios[i].base, pios[i].width, pios[i].label); - gidx = pios[i].gidx; - for (j = gidx; j < (gidx + pios[i].width); ++j) { - mask = 1 << (j - gidx); - printf("\tGPIO % 4d: %s %s [%c] %s\n", - gpios[j].num, - gpios[j].pio->sh_dir & mask ? "out" : " in", - gpio_get_value(gpios[j].num) ? "set" : "clr", - altera_pio_is_gidx_used(j) ? 'x' : ' ', - gpios[j].reqlabel); - } - } + return !!(readl(®s->data) & (1 << pin)); } -int gpio_request(unsigned gpio, const char *label) +static int altera_pio_set_value(struct udevice *dev, unsigned pin, int val) { - int gidx = altera_pio_gidx(gpio); - if (gidx < 0) - return gidx; - if (altera_pio_is_gidx_used(gidx)) - return -1; - - altera_pio_use_gidx(gidx, label); - return 0; -} + struct altera_pio_platdata *plat = dev_get_platdata(dev); + struct altera_pio_regs *const regs = plat->regs; -int gpio_free(unsigned gpio) -{ - int gidx = altera_pio_gidx(gpio); - if (gidx < 0) - return gidx; - if (!altera_pio_is_gidx_used(gidx)) - return -1; + if (val) + setbits_le32(®s->data, 1 << pin); + else + clrbits_le32(®s->data, 1 << pin); - altera_pio_unuse_gidx(gidx); return 0; } -int gpio_direction_input(unsigned gpio) +static int altera_pio_probe(struct udevice *dev) { - u32 mask; - struct altera_pio *pio; + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct altera_pio_platdata *plat = dev_get_platdata(dev); - pio = altera_pio_get_and_mask(gpio, &mask); - if (!pio) - return -1; - if (pio->iot == 'o') - return -1; + uc_priv->gpio_count = plat->gpio_count; + uc_priv->bank_name = plat->bank_name; - writel(pio->sh_dir &= ~mask, pio->base + ALTERA_PIO_DIR); return 0; } -int gpio_direction_output(unsigned gpio, int value) +static int altera_pio_ofdata_to_platdata(struct udevice *dev) { - u32 mask; - struct altera_pio *pio; + struct altera_pio_platdata *plat = dev_get_platdata(dev); - pio = altera_pio_get_and_mask(gpio, &mask); - if (!pio) - return -1; - if (pio->iot == 'i') - return -1; + plat->regs = ioremap(dev_get_addr(dev), + sizeof(struct altera_pio_regs)); + plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "width", 0); + plat->bank_name = fdt_getprop(gd->fdt_blob, dev->of_offset, + "gpio-bank-name", NULL); - value = (pio->negmask & mask) ? !value : value; - if (value) - pio->sh_data |= mask; - else - pio->sh_data &= ~mask; - writel(pio->sh_data, pio->base + ALTERA_PIO_DATA); - writel(pio->sh_dir |= mask, pio->base + ALTERA_PIO_DIR); return 0; } -int gpio_get_value(unsigned gpio) -{ - u32 mask; - struct altera_pio *pio; - u32 val; - - pio = altera_pio_get_and_mask(gpio, &mask); - if (!pio) - return -1; - - if ((pio->sh_dir & mask) || (pio->iot == 'o')) - val = pio->sh_data & mask; - else - val = readl(pio->base + ALTERA_PIO_DATA) & mask; - return (pio->negmask & mask) ? !val : val; -} - -void gpio_set_value(unsigned gpio, int value) -{ - u32 mask; - struct altera_pio *pio; - - pio = altera_pio_get_and_mask(gpio, &mask); - if (!pio) - return; - if (pio->iot == 'i') - return; - - value = (pio->negmask & mask) ? !value : value; - if (value) - pio->sh_data |= mask; - else - pio->sh_data &= ~mask; - writel(pio->sh_data, pio->base + ALTERA_PIO_DATA); - return; -} - -int gpio_is_valid(int number) -{ - int gidx = altera_pio_gidx(number); - - if (gidx < 0) - return 1; - return 0; -} +static const struct dm_gpio_ops altera_pio_ops = { + .direction_input = altera_pio_direction_input, + .direction_output = altera_pio_direction_output, + .get_value = altera_pio_get_value, + .set_value = altera_pio_set_value, +}; + +static const struct udevice_id altera_pio_ids[] = { + { .compatible = "altr,pio-1.0" }, + { } +}; + +U_BOOT_DRIVER(altera_pio) = { + .name = "altera_pio", + .id = UCLASS_GPIO, + .of_match = altera_pio_ids, + .ops = &altera_pio_ops, + .ofdata_to_platdata = altera_pio_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct altera_pio_platdata), + .probe = altera_pio_probe, +}; diff --git a/include/configs/nios2-generic.h b/include/configs/nios2-generic.h index dcb90de..90ccbd1 100644 --- a/include/configs/nios2-generic.h +++ b/include/configs/nios2-generic.h @@ -33,26 +33,6 @@ #define CONFIG_SYS_TIMER_RATE CONFIG_SYS_TIMER_FREQ /* - * STATUS LED - */ -#define CONFIG_ALTERA_PIO -#define CONFIG_SYS_ALTERA_PIO_NUM 1 -#define CONFIG_SYS_ALTERA_PIO_GPIO_NUM LED_PIO_WIDTH - -#define CONFIG_STATUS_LED /* Enable status driver */ -#define CONFIG_BOARD_SPECIFIC_LED -#define CONFIG_GPIO_LED /* Enable GPIO LED driver */ -#define CONFIG_GPIO /* Enable GPIO driver */ -#define LED_PIO_BASE USER_LED_PIO_8OUT_BASE -#define LED_PIO_WIDTH 8 -#define LED_PIO_RSTVAL 0xff - -#define STATUS_LED_BIT 0 /* Bit-0 on GPIO */ -#define STATUS_LED_STATE STATUS_LED_ON -#define STATUS_LED_PERIOD (CONFIG_SYS_HZ / 2) /* 500 msec */ -#define STATUS_LED_BOOT STATUS_LED_BIT - -/* * BOOTP options */ #define CONFIG_BOOTP_BOOTFILESIZE