| From 4949009eb8d40a441dcddcd96e101e77d31cf1b2 Mon Sep 17 00:00:00 2001 |
| From: Max Filippov <jcmvbkbc@gmail.com> |
| Date: Fri, 27 Feb 2015 06:28:00 +0300 |
| Subject: xtensa: xtfpga: fix hardware lockup caused by LCD driver |
| |
| From: Max Filippov <jcmvbkbc@gmail.com> |
| |
| commit 4949009eb8d40a441dcddcd96e101e77d31cf1b2 upstream. |
| |
| LCD driver is always built for the XTFPGA platform, but its base address |
| is not configurable, and is wrong for ML605/KC705. Its initialization |
| locks up KC705 board hardware. |
| |
| Make the whole driver optional, and its base address and bus width |
| configurable. Implement 4-bit bus access method. |
| |
| Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/xtensa/Kconfig | 30 ++++++++ |
| arch/xtensa/platforms/xtfpga/Makefile | 3 |
| arch/xtensa/platforms/xtfpga/include/platform/hardware.h | 3 |
| arch/xtensa/platforms/xtfpga/include/platform/lcd.h | 15 ++++ |
| arch/xtensa/platforms/xtfpga/lcd.c | 55 +++++++++------ |
| 5 files changed, 81 insertions(+), 25 deletions(-) |
| |
| --- a/arch/xtensa/Kconfig |
| +++ b/arch/xtensa/Kconfig |
| @@ -336,6 +336,36 @@ menu "Executable file formats" |
| |
| source "fs/Kconfig.binfmt" |
| |
| +config XTFPGA_LCD |
| + bool "Enable XTFPGA LCD driver" |
| + depends on XTENSA_PLATFORM_XTFPGA |
| + default n |
| + help |
| + There's a 2x16 LCD on most of XTFPGA boards, kernel may output |
| + progress messages there during bootup/shutdown. It may be useful |
| + during board bringup. |
| + |
| + If unsure, say N. |
| + |
| +config XTFPGA_LCD_BASE_ADDR |
| + hex "XTFPGA LCD base address" |
| + depends on XTFPGA_LCD |
| + default "0x0d0c0000" |
| + help |
| + Base address of the LCD controller inside KIO region. |
| + Different boards from XTFPGA family have LCD controller at different |
| + addresses. Please consult prototyping user guide for your board for |
| + the correct address. Wrong address here may lead to hardware lockup. |
| + |
| +config XTFPGA_LCD_8BIT_ACCESS |
| + bool "Use 8-bit access to XTFPGA LCD" |
| + depends on XTFPGA_LCD |
| + default n |
| + help |
| + LCD may be connected with 4- or 8-bit interface, 8-bit access may |
| + only be used with 8-bit interface. Please consult prototyping user |
| + guide for your board for the correct interface width. |
| + |
| endmenu |
| |
| source "net/Kconfig" |
| --- a/arch/xtensa/platforms/xtfpga/Makefile |
| +++ b/arch/xtensa/platforms/xtfpga/Makefile |
| @@ -6,4 +6,5 @@ |
| # |
| # Note 2! The CFLAGS definitions are in the main makefile... |
| |
| -obj-y = setup.o lcd.o |
| +obj-y += setup.o |
| +obj-$(CONFIG_XTFPGA_LCD) += lcd.o |
| --- a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h |
| +++ b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h |
| @@ -40,9 +40,6 @@ |
| |
| /* UART */ |
| #define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020) |
| -/* LCD instruction and data addresses. */ |
| -#define LCD_INSTR_ADDR ((char *)IOADDR(0x0D040000)) |
| -#define LCD_DATA_ADDR ((char *)IOADDR(0x0D040004)) |
| |
| /* Misc. */ |
| #define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000) |
| --- a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h |
| +++ b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h |
| @@ -11,10 +11,25 @@ |
| #ifndef __XTENSA_XTAVNET_LCD_H |
| #define __XTENSA_XTAVNET_LCD_H |
| |
| +#ifdef CONFIG_XTFPGA_LCD |
| /* Display string STR at position POS on the LCD. */ |
| void lcd_disp_at_pos(char *str, unsigned char pos); |
| |
| /* Shift the contents of the LCD display left or right. */ |
| void lcd_shiftleft(void); |
| void lcd_shiftright(void); |
| +#else |
| +static inline void lcd_disp_at_pos(char *str, unsigned char pos) |
| +{ |
| +} |
| + |
| +static inline void lcd_shiftleft(void) |
| +{ |
| +} |
| + |
| +static inline void lcd_shiftright(void) |
| +{ |
| +} |
| +#endif |
| + |
| #endif |
| --- a/arch/xtensa/platforms/xtfpga/lcd.c |
| +++ b/arch/xtensa/platforms/xtfpga/lcd.c |
| @@ -1,50 +1,63 @@ |
| /* |
| - * Driver for the LCD display on the Tensilica LX60 Board. |
| + * Driver for the LCD display on the Tensilica XTFPGA board family. |
| + * http://www.mytechcorp.com/cfdata/productFile/File1/MOC-16216B-B-A0A04.pdf |
| * |
| * This file is subject to the terms and conditions of the GNU General Public |
| * License. See the file "COPYING" in the main directory of this archive |
| * for more details. |
| * |
| * Copyright (C) 2001, 2006 Tensilica Inc. |
| + * Copyright (C) 2015 Cadence Design Systems Inc. |
| */ |
| |
| -/* |
| - * |
| - * FIXME: this code is from the examples from the LX60 user guide. |
| - * |
| - * The lcd_pause function does busy waiting, which is probably not |
| - * great. Maybe the code could be changed to use kernel timers, or |
| - * change the hardware to not need to wait. |
| - */ |
| - |
| +#include <linux/delay.h> |
| #include <linux/init.h> |
| #include <linux/io.h> |
| |
| #include <platform/hardware.h> |
| #include <platform/lcd.h> |
| -#include <linux/delay.h> |
| |
| -#define LCD_PAUSE_ITERATIONS 4000 |
| +/* LCD instruction and data addresses. */ |
| +#define LCD_INSTR_ADDR ((char *)IOADDR(CONFIG_XTFPGA_LCD_BASE_ADDR)) |
| +#define LCD_DATA_ADDR (LCD_INSTR_ADDR + 4) |
| + |
| #define LCD_CLEAR 0x1 |
| #define LCD_DISPLAY_ON 0xc |
| |
| /* 8bit and 2 lines display */ |
| #define LCD_DISPLAY_MODE8BIT 0x38 |
| +#define LCD_DISPLAY_MODE4BIT 0x28 |
| #define LCD_DISPLAY_POS 0x80 |
| #define LCD_SHIFT_LEFT 0x18 |
| #define LCD_SHIFT_RIGHT 0x1c |
| |
| +static void lcd_put_byte(u8 *addr, u8 data) |
| +{ |
| +#ifdef CONFIG_XTFPGA_LCD_8BIT_ACCESS |
| + ACCESS_ONCE(*addr) = data; |
| +#else |
| + ACCESS_ONCE(*addr) = data & 0xf0; |
| + ACCESS_ONCE(*addr) = (data << 4) & 0xf0; |
| +#endif |
| +} |
| + |
| static int __init lcd_init(void) |
| { |
| - *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; |
| + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; |
| mdelay(5); |
| - *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; |
| + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; |
| udelay(200); |
| - *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; |
| + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; |
| + udelay(50); |
| +#ifndef CONFIG_XTFPGA_LCD_8BIT_ACCESS |
| + ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE4BIT; |
| + udelay(50); |
| + lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_MODE4BIT); |
| udelay(50); |
| - *LCD_INSTR_ADDR = LCD_DISPLAY_ON; |
| +#endif |
| + lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_ON); |
| udelay(50); |
| - *LCD_INSTR_ADDR = LCD_CLEAR; |
| + lcd_put_byte(LCD_INSTR_ADDR, LCD_CLEAR); |
| mdelay(10); |
| lcd_disp_at_pos("XTENSA LINUX", 0); |
| return 0; |
| @@ -52,10 +65,10 @@ static int __init lcd_init(void) |
| |
| void lcd_disp_at_pos(char *str, unsigned char pos) |
| { |
| - *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos; |
| + lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_POS | pos); |
| udelay(100); |
| while (*str != 0) { |
| - *LCD_DATA_ADDR = *str; |
| + lcd_put_byte(LCD_DATA_ADDR, *str); |
| udelay(200); |
| str++; |
| } |
| @@ -63,13 +76,13 @@ void lcd_disp_at_pos(char *str, unsigned |
| |
| void lcd_shiftleft(void) |
| { |
| - *LCD_INSTR_ADDR = LCD_SHIFT_LEFT; |
| + lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_LEFT); |
| udelay(50); |
| } |
| |
| void lcd_shiftright(void) |
| { |
| - *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT; |
| + lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_RIGHT); |
| udelay(50); |
| } |
| |