Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4949009e authored by Max Filippov's avatar Max Filippov
Browse files

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: default avatarMax Filippov <jcmvbkbc@gmail.com>
parent bfa76d49
Loading
Loading
Loading
Loading
+30 −0
Original line number Original line Diff line number Diff line
@@ -428,6 +428,36 @@ config DEFAULT_MEM_SIZE


	  If unsure, leave the default value here.
	  If unsure, leave the default value here.


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"
+2 −1
Original line number Original line Diff line number Diff line
@@ -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
+0 −3
Original line number Original line Diff line number Diff line
@@ -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)
+15 −0
Original line number Original line Diff line number Diff line
@@ -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
+34 −21
Original line number Original line Diff line number Diff line
/*
/*
 * 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)


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)


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);
}
}