diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2015-02-26 22:28:00 -0500 |
---|---|---|
committer | Max Filippov <jcmvbkbc@gmail.com> | 2015-02-26 23:55:29 -0500 |
commit | 4949009eb8d40a441dcddcd96e101e77d31cf1b2 (patch) | |
tree | 8ce5900ef60e24168c654174cefaf47b02837fbe /arch/xtensa | |
parent | bfa76d49576599a4b9f9b7a71f23d73d6dcff735 (diff) |
xtensa: xtfpga: fix hardware lockup caused by LCD driver
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.
Cc: stable@vger.kernel.org
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'arch/xtensa')
-rw-r--r-- | arch/xtensa/Kconfig | 30 | ||||
-rw-r--r-- | arch/xtensa/platforms/xtfpga/Makefile | 3 | ||||
-rw-r--r-- | arch/xtensa/platforms/xtfpga/include/platform/hardware.h | 3 | ||||
-rw-r--r-- | arch/xtensa/platforms/xtfpga/include/platform/lcd.h | 15 | ||||
-rw-r--r-- | arch/xtensa/platforms/xtfpga/lcd.c | 55 |
5 files changed, 81 insertions, 25 deletions
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index e31d4949124a..87be10e8b57a 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig | |||
@@ -428,6 +428,36 @@ config DEFAULT_MEM_SIZE | |||
428 | 428 | ||
429 | If unsure, leave the default value here. | 429 | If unsure, leave the default value here. |
430 | 430 | ||
431 | config XTFPGA_LCD | ||
432 | bool "Enable XTFPGA LCD driver" | ||
433 | depends on XTENSA_PLATFORM_XTFPGA | ||
434 | default n | ||
435 | help | ||
436 | There's a 2x16 LCD on most of XTFPGA boards, kernel may output | ||
437 | progress messages there during bootup/shutdown. It may be useful | ||
438 | during board bringup. | ||
439 | |||
440 | If unsure, say N. | ||
441 | |||
442 | config XTFPGA_LCD_BASE_ADDR | ||
443 | hex "XTFPGA LCD base address" | ||
444 | depends on XTFPGA_LCD | ||
445 | default "0x0d0c0000" | ||
446 | help | ||
447 | Base address of the LCD controller inside KIO region. | ||
448 | Different boards from XTFPGA family have LCD controller at different | ||
449 | addresses. Please consult prototyping user guide for your board for | ||
450 | the correct address. Wrong address here may lead to hardware lockup. | ||
451 | |||
452 | config XTFPGA_LCD_8BIT_ACCESS | ||
453 | bool "Use 8-bit access to XTFPGA LCD" | ||
454 | depends on XTFPGA_LCD | ||
455 | default n | ||
456 | help | ||
457 | LCD may be connected with 4- or 8-bit interface, 8-bit access may | ||
458 | only be used with 8-bit interface. Please consult prototyping user | ||
459 | guide for your board for the correct interface width. | ||
460 | |||
431 | endmenu | 461 | endmenu |
432 | 462 | ||
433 | menu "Executable file formats" | 463 | menu "Executable file formats" |
diff --git a/arch/xtensa/platforms/xtfpga/Makefile b/arch/xtensa/platforms/xtfpga/Makefile index b9ae206340cd..7839d38b2337 100644 --- a/arch/xtensa/platforms/xtfpga/Makefile +++ b/arch/xtensa/platforms/xtfpga/Makefile | |||
@@ -6,4 +6,5 @@ | |||
6 | # | 6 | # |
7 | # Note 2! The CFLAGS definitions are in the main makefile... | 7 | # Note 2! The CFLAGS definitions are in the main makefile... |
8 | 8 | ||
9 | obj-y = setup.o lcd.o | 9 | obj-y += setup.o |
10 | obj-$(CONFIG_XTFPGA_LCD) += lcd.o | ||
diff --git a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h index 6edd20bb4565..4e0af2662a21 100644 --- a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h +++ b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h | |||
@@ -40,9 +40,6 @@ | |||
40 | 40 | ||
41 | /* UART */ | 41 | /* UART */ |
42 | #define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020) | 42 | #define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020) |
43 | /* LCD instruction and data addresses. */ | ||
44 | #define LCD_INSTR_ADDR ((char *)IOADDR(0x0D040000)) | ||
45 | #define LCD_DATA_ADDR ((char *)IOADDR(0x0D040004)) | ||
46 | 43 | ||
47 | /* Misc. */ | 44 | /* Misc. */ |
48 | #define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000) | 45 | #define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000) |
diff --git a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h index 0e435645af5a..4c8541ed1139 100644 --- a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h +++ b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h | |||
@@ -11,10 +11,25 @@ | |||
11 | #ifndef __XTENSA_XTAVNET_LCD_H | 11 | #ifndef __XTENSA_XTAVNET_LCD_H |
12 | #define __XTENSA_XTAVNET_LCD_H | 12 | #define __XTENSA_XTAVNET_LCD_H |
13 | 13 | ||
14 | #ifdef CONFIG_XTFPGA_LCD | ||
14 | /* Display string STR at position POS on the LCD. */ | 15 | /* Display string STR at position POS on the LCD. */ |
15 | void lcd_disp_at_pos(char *str, unsigned char pos); | 16 | void lcd_disp_at_pos(char *str, unsigned char pos); |
16 | 17 | ||
17 | /* Shift the contents of the LCD display left or right. */ | 18 | /* Shift the contents of the LCD display left or right. */ |
18 | void lcd_shiftleft(void); | 19 | void lcd_shiftleft(void); |
19 | void lcd_shiftright(void); | 20 | void lcd_shiftright(void); |
21 | #else | ||
22 | static inline void lcd_disp_at_pos(char *str, unsigned char pos) | ||
23 | { | ||
24 | } | ||
25 | |||
26 | static inline void lcd_shiftleft(void) | ||
27 | { | ||
28 | } | ||
29 | |||
30 | static inline void lcd_shiftright(void) | ||
31 | { | ||
32 | } | ||
33 | #endif | ||
34 | |||
20 | #endif | 35 | #endif |
diff --git a/arch/xtensa/platforms/xtfpga/lcd.c b/arch/xtensa/platforms/xtfpga/lcd.c index 2872301598df..4dc0c1b43f4b 100644 --- a/arch/xtensa/platforms/xtfpga/lcd.c +++ b/arch/xtensa/platforms/xtfpga/lcd.c | |||
@@ -1,50 +1,63 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for the LCD display on the Tensilica LX60 Board. | 2 | * Driver for the LCD display on the Tensilica XTFPGA board family. |
3 | * http://www.mytechcorp.com/cfdata/productFile/File1/MOC-16216B-B-A0A04.pdf | ||
3 | * | 4 | * |
4 | * This file is subject to the terms and conditions of the GNU General Public | 5 | * This file is subject to the terms and conditions of the GNU General Public |
5 | * License. See the file "COPYING" in the main directory of this archive | 6 | * License. See the file "COPYING" in the main directory of this archive |
6 | * for more details. | 7 | * for more details. |
7 | * | 8 | * |
8 | * Copyright (C) 2001, 2006 Tensilica Inc. | 9 | * Copyright (C) 2001, 2006 Tensilica Inc. |
10 | * Copyright (C) 2015 Cadence Design Systems Inc. | ||
9 | */ | 11 | */ |
10 | 12 | ||
11 | /* | 13 | #include <linux/delay.h> |
12 | * | ||
13 | * FIXME: this code is from the examples from the LX60 user guide. | ||
14 | * | ||
15 | * The lcd_pause function does busy waiting, which is probably not | ||
16 | * great. Maybe the code could be changed to use kernel timers, or | ||
17 | * change the hardware to not need to wait. | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | 14 | #include <linux/init.h> |
21 | #include <linux/io.h> | 15 | #include <linux/io.h> |
22 | 16 | ||
23 | #include <platform/hardware.h> | 17 | #include <platform/hardware.h> |
24 | #include <platform/lcd.h> | 18 | #include <platform/lcd.h> |
25 | #include <linux/delay.h> | ||
26 | 19 | ||
27 | #define LCD_PAUSE_ITERATIONS 4000 | 20 | /* LCD instruction and data addresses. */ |
21 | #define LCD_INSTR_ADDR ((char *)IOADDR(CONFIG_XTFPGA_LCD_BASE_ADDR)) | ||
22 | #define LCD_DATA_ADDR (LCD_INSTR_ADDR + 4) | ||
23 | |||
28 | #define LCD_CLEAR 0x1 | 24 | #define LCD_CLEAR 0x1 |
29 | #define LCD_DISPLAY_ON 0xc | 25 | #define LCD_DISPLAY_ON 0xc |
30 | 26 | ||
31 | /* 8bit and 2 lines display */ | 27 | /* 8bit and 2 lines display */ |
32 | #define LCD_DISPLAY_MODE8BIT 0x38 | 28 | #define LCD_DISPLAY_MODE8BIT 0x38 |
29 | #define LCD_DISPLAY_MODE4BIT 0x28 | ||
33 | #define LCD_DISPLAY_POS 0x80 | 30 | #define LCD_DISPLAY_POS 0x80 |
34 | #define LCD_SHIFT_LEFT 0x18 | 31 | #define LCD_SHIFT_LEFT 0x18 |
35 | #define LCD_SHIFT_RIGHT 0x1c | 32 | #define LCD_SHIFT_RIGHT 0x1c |
36 | 33 | ||
34 | static void lcd_put_byte(u8 *addr, u8 data) | ||
35 | { | ||
36 | #ifdef CONFIG_XTFPGA_LCD_8BIT_ACCESS | ||
37 | ACCESS_ONCE(*addr) = data; | ||
38 | #else | ||
39 | ACCESS_ONCE(*addr) = data & 0xf0; | ||
40 | ACCESS_ONCE(*addr) = (data << 4) & 0xf0; | ||
41 | #endif | ||
42 | } | ||
43 | |||
37 | static int __init lcd_init(void) | 44 | static int __init lcd_init(void) |
38 | { | 45 | { |
39 | *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; | 46 | ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; |
40 | mdelay(5); | 47 | mdelay(5); |
41 | *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; | 48 | ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; |
42 | udelay(200); | 49 | udelay(200); |
43 | *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; | 50 | ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT; |
51 | udelay(50); | ||
52 | #ifndef CONFIG_XTFPGA_LCD_8BIT_ACCESS | ||
53 | ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE4BIT; | ||
54 | udelay(50); | ||
55 | lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_MODE4BIT); | ||
44 | udelay(50); | 56 | udelay(50); |
45 | *LCD_INSTR_ADDR = LCD_DISPLAY_ON; | 57 | #endif |
58 | lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_ON); | ||
46 | udelay(50); | 59 | udelay(50); |
47 | *LCD_INSTR_ADDR = LCD_CLEAR; | 60 | lcd_put_byte(LCD_INSTR_ADDR, LCD_CLEAR); |
48 | mdelay(10); | 61 | mdelay(10); |
49 | lcd_disp_at_pos("XTENSA LINUX", 0); | 62 | lcd_disp_at_pos("XTENSA LINUX", 0); |
50 | return 0; | 63 | return 0; |
@@ -52,10 +65,10 @@ static int __init lcd_init(void) | |||
52 | 65 | ||
53 | void lcd_disp_at_pos(char *str, unsigned char pos) | 66 | void lcd_disp_at_pos(char *str, unsigned char pos) |
54 | { | 67 | { |
55 | *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos; | 68 | lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_POS | pos); |
56 | udelay(100); | 69 | udelay(100); |
57 | while (*str != 0) { | 70 | while (*str != 0) { |
58 | *LCD_DATA_ADDR = *str; | 71 | lcd_put_byte(LCD_DATA_ADDR, *str); |
59 | udelay(200); | 72 | udelay(200); |
60 | str++; | 73 | str++; |
61 | } | 74 | } |
@@ -63,13 +76,13 @@ void lcd_disp_at_pos(char *str, unsigned char pos) | |||
63 | 76 | ||
64 | void lcd_shiftleft(void) | 77 | void lcd_shiftleft(void) |
65 | { | 78 | { |
66 | *LCD_INSTR_ADDR = LCD_SHIFT_LEFT; | 79 | lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_LEFT); |
67 | udelay(50); | 80 | udelay(50); |
68 | } | 81 | } |
69 | 82 | ||
70 | void lcd_shiftright(void) | 83 | void lcd_shiftright(void) |
71 | { | 84 | { |
72 | *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT; | 85 | lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_RIGHT); |
73 | udelay(50); | 86 | udelay(50); |
74 | } | 87 | } |
75 | 88 | ||