Commit 52c464f2 authored by Max Filippov's avatar Max Filippov Committed by Luis Henriques

xtensa: xtfpga: fix hardware lockup caused by LCD driver

commit 4949009e 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: default avatarMax Filippov <jcmvbkbc@gmail.com>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 9989a31c
...@@ -348,6 +348,36 @@ source "drivers/pcmcia/Kconfig" ...@@ -348,6 +348,36 @@ source "drivers/pcmcia/Kconfig"
source "drivers/pci/hotplug/Kconfig" source "drivers/pci/hotplug/Kconfig"
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 endmenu
menu "Executable file formats" menu "Executable file formats"
......
...@@ -6,4 +6,5 @@ ...@@ -6,4 +6,5 @@
# #
# Note 2! The CFLAGS definitions are in the main makefile... # 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
...@@ -40,9 +40,6 @@ ...@@ -40,9 +40,6 @@
/* UART */ /* UART */
#define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020) #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. */ /* Misc. */
#define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000) #define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000)
......
...@@ -11,10 +11,25 @@ ...@@ -11,10 +11,25 @@
#ifndef __XTENSA_XTAVNET_LCD_H #ifndef __XTENSA_XTAVNET_LCD_H
#define __XTENSA_XTAVNET_LCD_H #define __XTENSA_XTAVNET_LCD_H
#ifdef CONFIG_XTFPGA_LCD
/* Display string STR at position POS on the LCD. */ /* Display string STR at position POS on the LCD. */
void lcd_disp_at_pos(char *str, unsigned char pos); void lcd_disp_at_pos(char *str, unsigned char pos);
/* Shift the contents of the LCD display left or right. */ /* Shift the contents of the LCD display left or right. */
void lcd_shiftleft(void); void lcd_shiftleft(void);
void lcd_shiftright(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 #endif
/* /*
* 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 * 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 * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
* *
* Copyright (C) 2001, 2006 Tensilica Inc. * Copyright (C) 2001, 2006 Tensilica Inc.
* Copyright (C) 2015 Cadence Design Systems Inc.
*/ */
/* #include <linux/delay.h>
*
* 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/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <platform/hardware.h> #include <platform/hardware.h>
#include <platform/lcd.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_CLEAR 0x1
#define LCD_DISPLAY_ON 0xc #define LCD_DISPLAY_ON 0xc
/* 8bit and 2 lines display */ /* 8bit and 2 lines display */
#define LCD_DISPLAY_MODE8BIT 0x38 #define LCD_DISPLAY_MODE8BIT 0x38
#define LCD_DISPLAY_MODE4BIT 0x28
#define LCD_DISPLAY_POS 0x80 #define LCD_DISPLAY_POS 0x80
#define LCD_SHIFT_LEFT 0x18 #define LCD_SHIFT_LEFT 0x18
#define LCD_SHIFT_RIGHT 0x1c #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) static int __init lcd_init(void)
{ {
*LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
mdelay(5); mdelay(5);
*LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; ACCESS_ONCE(*LCD_INSTR_ADDR) = LCD_DISPLAY_MODE8BIT;
udelay(200); 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); udelay(50);
*LCD_INSTR_ADDR = LCD_DISPLAY_ON; #endif
lcd_put_byte(LCD_INSTR_ADDR, LCD_DISPLAY_ON);
udelay(50); udelay(50);
*LCD_INSTR_ADDR = LCD_CLEAR; lcd_put_byte(LCD_INSTR_ADDR, LCD_CLEAR);
mdelay(10); mdelay(10);
lcd_disp_at_pos("XTENSA LINUX", 0); lcd_disp_at_pos("XTENSA LINUX", 0);
return 0; return 0;
...@@ -52,10 +65,10 @@ static int __init lcd_init(void) ...@@ -52,10 +65,10 @@ static int __init lcd_init(void)
void lcd_disp_at_pos(char *str, unsigned char pos) 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); udelay(100);
while (*str != 0) { while (*str != 0) {
*LCD_DATA_ADDR = *str; lcd_put_byte(LCD_DATA_ADDR, *str);
udelay(200); udelay(200);
str++; str++;
} }
...@@ -63,13 +76,13 @@ void lcd_disp_at_pos(char *str, unsigned char pos) ...@@ -63,13 +76,13 @@ void lcd_disp_at_pos(char *str, unsigned char pos)
void lcd_shiftleft(void) void lcd_shiftleft(void)
{ {
*LCD_INSTR_ADDR = LCD_SHIFT_LEFT; lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_LEFT);
udelay(50); udelay(50);
} }
void lcd_shiftright(void) void lcd_shiftright(void)
{ {
*LCD_INSTR_ADDR = LCD_SHIFT_RIGHT; lcd_put_byte(LCD_INSTR_ADDR, LCD_SHIFT_RIGHT);
udelay(50); udelay(50);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment