2005-04-16 15:20:36 -07:00
/*
* arch / m68k / mvme16x / config . c
*
* Copyright ( C ) 1995 Richard Hirst [ richard @ sleepie . demon . co . uk ]
*
* Based on :
*
* linux / amiga / config . c
*
* Copyright ( C ) 1993 Hamish Macdonald
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file README . legal in the main directory of this archive
* for more details .
*/
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/mm.h>
2008-10-03 22:42:36 +04:00
# include <linux/seq_file.h>
2005-04-16 15:20:36 -07:00
# include <linux/tty.h>
2018-12-01 11:53:10 +11:00
# include <linux/clocksource.h>
2005-04-16 15:20:36 -07:00
# include <linux/console.h>
# include <linux/linkage.h>
# include <linux/init.h>
# include <linux/major.h>
# include <linux/genhd.h>
# include <linux/rtc.h>
# include <linux/interrupt.h>
2008-02-04 22:30:27 -08:00
# include <linux/module.h>
2005-04-16 15:20:36 -07:00
# include <asm/bootinfo.h>
2013-10-02 11:37:33 +02:00
# include <asm/bootinfo-vme.h>
2013-10-04 11:41:24 +02:00
# include <asm/byteorder.h>
2005-04-16 15:20:36 -07:00
# include <asm/setup.h>
# include <asm/irq.h>
# include <asm/traps.h>
# include <asm/machdep.h>
# include <asm/mvme16xhw.h>
extern t_bdid mvme_bdid ;
static MK48T08ptr_t volatile rtc = ( MK48T08ptr_t ) MVME_RTC_BASE ;
static void mvme16x_get_model ( char * model ) ;
2020-09-24 17:29:17 +02:00
extern void mvme16x_sched_init ( void ) ;
2005-04-16 15:20:36 -07:00
extern int mvme16x_hwclk ( int , struct rtc_time * ) ;
extern void mvme16x_reset ( void ) ;
int bcd2int ( unsigned char b ) ;
unsigned short mvme16x_config ;
2008-02-04 22:30:27 -08:00
EXPORT_SYMBOL ( mvme16x_config ) ;
2005-04-16 15:20:36 -07:00
2013-06-25 21:15:24 +02:00
int __init mvme16x_parse_bootinfo ( const struct bi_record * bi )
2005-04-16 15:20:36 -07:00
{
2013-10-04 11:41:24 +02:00
uint16_t tag = be16_to_cpu ( bi - > tag ) ;
if ( tag = = BI_VME_TYPE | | tag = = BI_VME_BRDINFO )
2005-04-16 15:20:36 -07:00
return 0 ;
else
return 1 ;
}
void mvme16x_reset ( void )
{
2016-12-06 17:10:23 +01:00
pr_info ( " \r \n \n Called mvme16x_reset \r \n "
" \r \r \r \r \r \r \r \r \r \r \r \r \r \r \r \r \r \r " ) ;
2005-04-16 15:20:36 -07:00
/* The string of returns is to delay the reset until the whole
* message is output . Assert reset bit in GCSR */
* ( volatile char * ) 0xfff40107 = 0x80 ;
}
static void mvme16x_get_model ( char * model )
{
p_bdid p = & mvme_bdid ;
char suf [ 4 ] ;
suf [ 1 ] = p - > brdsuffix [ 0 ] ;
suf [ 2 ] = p - > brdsuffix [ 1 ] ;
suf [ 3 ] = ' \0 ' ;
suf [ 0 ] = suf [ 1 ] ? ' - ' : ' \0 ' ;
2013-10-04 11:41:24 +02:00
sprintf ( model , " Motorola MVME%x%s " , be16_to_cpu ( p - > brdno ) , suf ) ;
2005-04-16 15:20:36 -07:00
}
2008-10-03 22:42:36 +04:00
static void mvme16x_get_hardware_list ( struct seq_file * m )
2005-04-16 15:20:36 -07:00
{
2013-10-04 11:41:24 +02:00
uint16_t brdno = be16_to_cpu ( mvme_bdid . brdno ) ;
2005-04-16 15:20:36 -07:00
2013-10-04 11:41:24 +02:00
if ( brdno = = 0x0162 | | brdno = = 0x0172 )
2005-04-16 15:20:36 -07:00
{
unsigned char rev = * ( unsigned char * ) MVME162_VERSION_REG ;
2008-10-03 22:42:36 +04:00
seq_printf ( m , " VMEchip2 %spresent \n " ,
2005-04-16 15:20:36 -07:00
rev & MVME16x_CONFIG_NO_VMECHIP2 ? " NOT " : " " ) ;
2008-10-03 22:42:36 +04:00
seq_printf ( m , " SCSI interface %spresent \n " ,
2005-04-16 15:20:36 -07:00
rev & MVME16x_CONFIG_NO_SCSICHIP ? " NOT " : " " ) ;
2008-10-03 22:42:36 +04:00
seq_printf ( m , " Ethernet i/f %spresent \n " ,
2005-04-16 15:20:36 -07:00
rev & MVME16x_CONFIG_NO_ETHERNET ? " NOT " : " " ) ;
}
}
2006-06-25 05:47:06 -07:00
/*
* This function is called during kernel startup to initialize
* the mvme16x IRQ handling routines . Should probably ensure
* that the base vectors for the VMEChip2 and PCCChip2 are valid .
*/
2007-07-20 04:33:28 +01:00
static void __init mvme16x_init_IRQ ( void )
2006-06-25 05:47:06 -07:00
{
2011-09-11 11:54:50 +02:00
m68k_setup_user_interrupt ( VEC_USER , 192 ) ;
2006-06-25 05:47:06 -07:00
}
2005-04-16 15:20:36 -07:00
2018-12-01 11:53:10 +11:00
# define PCC2CHIP (0xfff42000)
# define PCCSCCMICR (PCC2CHIP + 0x1d)
# define PCCSCCTICR (PCC2CHIP + 0x1e)
# define PCCSCCRICR (PCC2CHIP + 0x1f)
# define PCCTPIACKR (PCC2CHIP + 0x25)
2008-11-20 13:47:18 +01:00
# ifdef CONFIG_EARLY_PRINTK
/**** cd2401 registers ****/
# define CD2401_ADDR (0xfff45000)
# define CyGFRCR (0x81)
# define CyCCR (0x13)
# define CyCLR_CHAN (0x40)
# define CyINIT_CHAN (0x20)
# define CyCHIP_RESET (0x10)
# define CyENB_XMTR (0x08)
# define CyDIS_XMTR (0x04)
# define CyENB_RCVR (0x02)
# define CyDIS_RCVR (0x01)
# define CyCAR (0xee)
# define CyIER (0x11)
# define CyMdmCh (0x80)
# define CyRxExc (0x20)
# define CyRxData (0x08)
# define CyTxMpty (0x02)
# define CyTxRdy (0x01)
# define CyLICR (0x26)
# define CyRISR (0x89)
# define CyTIMEOUT (0x80)
# define CySPECHAR (0x70)
# define CyOVERRUN (0x08)
# define CyPARITY (0x04)
# define CyFRAME (0x02)
# define CyBREAK (0x01)
# define CyREOIR (0x84)
# define CyTEOIR (0x85)
# define CyMEOIR (0x86)
# define CyNOTRANS (0x08)
# define CyRFOC (0x30)
# define CyRDR (0xf8)
# define CyTDR (0xf8)
# define CyMISR (0x8b)
# define CyRISR (0x89)
# define CyTISR (0x8a)
# define CyMSVR1 (0xde)
# define CyMSVR2 (0xdf)
# define CyDSR (0x80)
# define CyDCD (0x40)
# define CyCTS (0x20)
# define CyDTR (0x02)
# define CyRTS (0x01)
# define CyRTPRL (0x25)
# define CyRTPRH (0x24)
# define CyCOR1 (0x10)
# define CyPARITY_NONE (0x00)
# define CyPARITY_E (0x40)
# define CyPARITY_O (0xC0)
# define Cy_5_BITS (0x04)
# define Cy_6_BITS (0x05)
# define Cy_7_BITS (0x06)
# define Cy_8_BITS (0x07)
# define CyCOR2 (0x17)
# define CyETC (0x20)
# define CyCtsAE (0x02)
# define CyCOR3 (0x16)
# define Cy_1_STOP (0x02)
# define Cy_2_STOP (0x04)
# define CyCOR4 (0x15)
# define CyREC_FIFO (0x0F) /* Receive FIFO threshold */
# define CyCOR5 (0x14)
# define CyCOR6 (0x18)
# define CyCOR7 (0x07)
# define CyRBPR (0xcb)
# define CyRCOR (0xc8)
# define CyTBPR (0xc3)
# define CyTCOR (0xc0)
# define CySCHR1 (0x1f)
# define CySCHR2 (0x1e)
# define CyTPR (0xda)
# define CyPILR1 (0xe3)
# define CyPILR2 (0xe0)
# define CyPILR3 (0xe1)
# define CyCMR (0x1b)
# define CyASYNC (0x02)
# define CyLICR (0x26)
# define CyLIVR (0x09)
# define CySCRL (0x23)
# define CySCRH (0x22)
# define CyTFTC (0x80)
2014-04-12 23:49:30 +10:00
void mvme16x_cons_write ( struct console * co , const char * str , unsigned count )
2008-11-20 13:47:18 +01:00
{
volatile unsigned char * base_addr = ( u_char * ) CD2401_ADDR ;
volatile u_char sink ;
u_char ier ;
int port ;
u_char do_lf = 0 ;
int i = 0 ;
/* Ensure transmitter is enabled! */
port = 0 ;
base_addr [ CyCAR ] = ( u_char ) port ;
while ( base_addr [ CyCCR ] )
;
base_addr [ CyCCR ] = CyENB_XMTR ;
ier = base_addr [ CyIER ] ;
base_addr [ CyIER ] = CyTxMpty ;
while ( 1 ) {
2018-12-01 11:53:10 +11:00
if ( in_8 ( PCCSCCTICR ) & 0x20 )
2008-11-20 13:47:18 +01:00
{
/* We have a Tx int. Acknowledge it */
2018-12-01 11:53:10 +11:00
sink = in_8 ( PCCTPIACKR ) ;
2008-11-20 13:47:18 +01:00
if ( ( base_addr [ CyLICR ] > > 2 ) = = port ) {
if ( i = = count ) {
/* Last char of string is now output */
base_addr [ CyTEOIR ] = CyNOTRANS ;
break ;
}
if ( do_lf ) {
base_addr [ CyTDR ] = ' \n ' ;
str + + ;
i + + ;
do_lf = 0 ;
}
else if ( * str = = ' \n ' ) {
base_addr [ CyTDR ] = ' \r ' ;
do_lf = 1 ;
}
else {
base_addr [ CyTDR ] = * str + + ;
i + + ;
}
base_addr [ CyTEOIR ] = 0 ;
}
else
base_addr [ CyTEOIR ] = CyNOTRANS ;
}
}
base_addr [ CyIER ] = ier ;
}
# endif
2005-04-16 15:20:36 -07:00
void __init config_mvme16x ( void )
{
p_bdid p = & mvme_bdid ;
char id [ 40 ] ;
2013-10-04 11:41:24 +02:00
uint16_t brdno = be16_to_cpu ( p - > brdno ) ;
2005-04-16 15:20:36 -07:00
mach_sched_init = mvme16x_sched_init ;
mach_init_IRQ = mvme16x_init_IRQ ;
mach_hwclk = mvme16x_hwclk ;
mach_reset = mvme16x_reset ;
mach_get_model = mvme16x_get_model ;
mach_get_hardware_list = mvme16x_get_hardware_list ;
/* Report board revision */
if ( strncmp ( " BDID " , p - > bdid , 4 ) )
{
2016-12-06 17:10:23 +01:00
pr_crit ( " Bug call .BRD_ID returned garbage - giving up \n " ) ;
2005-04-16 15:20:36 -07:00
while ( 1 )
;
}
/* Board type is only set by newer versions of vmelilo/tftplilo */
if ( vme_brdtype = = 0 )
2013-10-04 11:41:24 +02:00
vme_brdtype = brdno ;
2005-04-16 15:20:36 -07:00
mvme16x_get_model ( id ) ;
2016-12-06 17:10:23 +01:00
pr_info ( " BRD_ID: %s BUG %x.%x %02x/%02x/%02x \n " , id , p - > rev > > 4 ,
p - > rev & 0xf , p - > yr , p - > mth , p - > day ) ;
2013-10-04 11:41:24 +02:00
if ( brdno = = 0x0162 | | brdno = = 0x172 )
2005-04-16 15:20:36 -07:00
{
unsigned char rev = * ( unsigned char * ) MVME162_VERSION_REG ;
mvme16x_config = rev | MVME16x_CONFIG_GOT_SCCA ;
2016-12-06 17:10:23 +01:00
pr_info ( " MVME%x Hardware status: \n " , brdno ) ;
pr_info ( " CPU Type 68%s040 \n " ,
rev & MVME16x_CONFIG_GOT_FPU ? " " : " LC " ) ;
pr_info ( " CPU clock %dMHz \n " ,
rev & MVME16x_CONFIG_SPEED_32 ? 32 : 25 ) ;
pr_info ( " VMEchip2 %spresent \n " ,
rev & MVME16x_CONFIG_NO_VMECHIP2 ? " NOT " : " " ) ;
pr_info ( " SCSI interface %spresent \n " ,
rev & MVME16x_CONFIG_NO_SCSICHIP ? " NOT " : " " ) ;
pr_info ( " Ethernet interface %spresent \n " ,
rev & MVME16x_CONFIG_NO_ETHERNET ? " NOT " : " " ) ;
2005-04-16 15:20:36 -07:00
}
else
{
mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401 ;
}
}
2006-10-07 14:16:45 +01:00
static irqreturn_t mvme16x_abort_int ( int irq , void * dev_id )
2005-04-16 15:20:36 -07:00
{
unsigned long * new = ( unsigned long * ) vectors ;
unsigned long * old = ( unsigned long * ) 0xffe00000 ;
volatile unsigned char uc , * ucp ;
2013-10-04 11:41:24 +02:00
uint16_t brdno = be16_to_cpu ( mvme_bdid . brdno ) ;
2005-04-16 15:20:36 -07:00
2013-10-04 11:41:24 +02:00
if ( brdno = = 0x0162 | | brdno = = 0x172 )
2005-04-16 15:20:36 -07:00
{
ucp = ( volatile unsigned char * ) 0xfff42043 ;
uc = * ucp | 8 ;
* ucp = uc ;
}
else
{
* ( volatile unsigned long * ) 0xfff40074 = 0x40000000 ;
}
* ( new + 4 ) = * ( old + 4 ) ; /* Illegal instruction */
* ( new + 9 ) = * ( old + 9 ) ; /* Trace */
* ( new + 47 ) = * ( old + 47 ) ; /* Trap #15 */
2013-10-04 11:41:24 +02:00
if ( brdno = = 0x0162 | | brdno = = 0x172 )
2005-04-16 15:20:36 -07:00
* ( new + 0x5e ) = * ( old + 0x5e ) ; /* ABORT switch */
else
* ( new + 0x6e ) = * ( old + 0x6e ) ; /* ABORT switch */
return IRQ_HANDLED ;
}
2018-12-01 11:53:10 +11:00
static u64 mvme16x_read_clk ( struct clocksource * cs ) ;
static struct clocksource mvme16x_clk = {
. name = " pcc " ,
. rating = 250 ,
. read = mvme16x_read_clk ,
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
static u32 clk_total ;
# define PCC_TIMER_CLOCK_FREQ 1000000
# define PCC_TIMER_CYCLES (PCC_TIMER_CLOCK_FREQ / HZ)
2018-12-01 11:53:10 +11:00
# define PCCTCMP1 (PCC2CHIP + 0x04)
# define PCCTCNT1 (PCC2CHIP + 0x08)
# define PCCTOVR1 (PCC2CHIP + 0x17)
# define PCCTIC1 (PCC2CHIP + 0x1b)
# define PCCTOVR1_TIC_EN 0x01
# define PCCTOVR1_COC_EN 0x02
# define PCCTOVR1_OVR_CLR 0x04
2021-03-30 18:37:51 +11:00
# define PCCTIC1_INT_LEVEL 6
2018-12-01 11:53:10 +11:00
# define PCCTIC1_INT_CLR 0x08
# define PCCTIC1_INT_EN 0x10
2006-10-07 14:16:45 +01:00
static irqreturn_t mvme16x_timer_int ( int irq , void * dev_id )
2005-04-16 15:20:36 -07:00
{
2018-12-01 11:53:10 +11:00
unsigned long flags ;
local_irq_save ( flags ) ;
2021-03-30 18:37:51 +11:00
out_8 ( PCCTOVR1 , PCCTOVR1_OVR_CLR | PCCTOVR1_TIC_EN | PCCTOVR1_COC_EN ) ;
out_8 ( PCCTIC1 , PCCTIC1_INT_EN | PCCTIC1_INT_CLR | PCCTIC1_INT_LEVEL ) ;
2018-12-01 11:53:10 +11:00
clk_total + = PCC_TIMER_CYCLES ;
2020-09-24 17:21:00 +02:00
legacy_timer_tick ( 1 ) ;
2018-12-01 11:53:10 +11:00
local_irq_restore ( flags ) ;
return IRQ_HANDLED ;
2005-04-16 15:20:36 -07:00
}
2020-09-24 17:29:17 +02:00
void mvme16x_sched_init ( void )
2005-04-16 15:20:36 -07:00
{
2013-10-04 11:41:24 +02:00
uint16_t brdno = be16_to_cpu ( mvme_bdid . brdno ) ;
2005-04-16 15:20:36 -07:00
int irq ;
/* Using PCCchip2 or MC2 chip tick timer 1 */
2018-12-01 11:53:10 +11:00
if ( request_irq ( MVME16x_IRQ_TIMER , mvme16x_timer_int , IRQF_TIMER , " timer " ,
2020-09-24 17:21:00 +02:00
NULL ) )
2005-04-16 15:20:36 -07:00
panic ( " Couldn't register timer int " ) ;
2021-03-30 18:37:51 +11:00
out_be32 ( PCCTCNT1 , 0 ) ;
out_be32 ( PCCTCMP1 , PCC_TIMER_CYCLES ) ;
out_8 ( PCCTOVR1 , PCCTOVR1_OVR_CLR | PCCTOVR1_TIC_EN | PCCTOVR1_COC_EN ) ;
out_8 ( PCCTIC1 , PCCTIC1_INT_EN | PCCTIC1_INT_CLR | PCCTIC1_INT_LEVEL ) ;
2018-12-01 11:53:10 +11:00
clocksource_register_hz ( & mvme16x_clk , PCC_TIMER_CLOCK_FREQ ) ;
2013-10-04 11:41:24 +02:00
if ( brdno = = 0x0162 | | brdno = = 0x172 )
2005-04-16 15:20:36 -07:00
irq = MVME162_IRQ_ABORT ;
else
irq = MVME167_IRQ_ABORT ;
if ( request_irq ( irq , mvme16x_abort_int , 0 ,
" abort " , mvme16x_abort_int ) )
panic ( " Couldn't register abort int " ) ;
}
2018-12-01 11:53:10 +11:00
static u64 mvme16x_read_clk ( struct clocksource * cs )
2005-04-16 15:20:36 -07:00
{
2018-12-01 11:53:10 +11:00
unsigned long flags ;
2018-12-01 11:53:10 +11:00
u8 overflow , tmp ;
2018-12-01 11:53:10 +11:00
u32 ticks ;
local_irq_save ( flags ) ;
2018-12-01 11:53:10 +11:00
tmp = in_8 ( PCCTOVR1 ) > > 4 ;
ticks = in_be32 ( PCCTCNT1 ) ;
overflow = in_8 ( PCCTOVR1 ) > > 4 ;
if ( overflow ! = tmp )
ticks = in_be32 ( PCCTCNT1 ) ;
ticks + = overflow * PCC_TIMER_CYCLES ;
2018-12-01 11:53:10 +11:00
ticks + = clk_total ;
local_irq_restore ( flags ) ;
return ticks ;
2005-04-16 15:20:36 -07:00
}
int bcd2int ( unsigned char b )
{
return ( ( b > > 4 ) * 10 + ( b & 15 ) ) ;
}
int mvme16x_hwclk ( int op , struct rtc_time * t )
{
# warning check me!
if ( ! op ) {
rtc - > ctrl = RTC_READ ;
t - > tm_year = bcd2int ( rtc - > bcd_year ) ;
m68k: Fix off-by-one calendar month
This fixes a bug in read_persistent_clock() which causes the system
clock to lag the Real Time Clock by one month. The problem was noticed
on a Mac, but theoretically it must also affect Atari, BVME6000 and Q40.
The tm_mon value in the struct rtc_time passed to mach_hwclk() is
zero-based, and atari_mste_hwclk(), atari_tt_hwclk(), bvme6000_hwclk(),
mac_hwclk() and q40_hwclk() all make this adjustment. Unfortunately,
dn_dummy_hwclk(), mvme147_hwclk(), mvme16x_hwclk(), sun3_hwclk() and
sun3x_hwclk() fail to decrement tm_mon. Also m68328_hwclk() assumes
a one-based tm_mon.
Bring these platforms into line and fix read_persistent_clock() so it
works correctly on all m68k platforms.
The datasheets for the RTC devices found on the affected platforms
all confirm that the year is stored as a value in the range 0-99 and
the month is stored as a value in the range 1-12. Please refer to the
datasheets for MC146818 (Apollo), DS1643 (MVME), ICM7170 (Sun 3)
and M48T02 (Sun 3x).
Reported-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
2018-04-23 11:02:57 +10:00
t - > tm_mon = bcd2int ( rtc - > bcd_mth ) - 1 ;
2005-04-16 15:20:36 -07:00
t - > tm_mday = bcd2int ( rtc - > bcd_dom ) ;
t - > tm_hour = bcd2int ( rtc - > bcd_hr ) ;
t - > tm_min = bcd2int ( rtc - > bcd_min ) ;
t - > tm_sec = bcd2int ( rtc - > bcd_sec ) ;
rtc - > ctrl = 0 ;
m68k: Fix off-by-one calendar month
This fixes a bug in read_persistent_clock() which causes the system
clock to lag the Real Time Clock by one month. The problem was noticed
on a Mac, but theoretically it must also affect Atari, BVME6000 and Q40.
The tm_mon value in the struct rtc_time passed to mach_hwclk() is
zero-based, and atari_mste_hwclk(), atari_tt_hwclk(), bvme6000_hwclk(),
mac_hwclk() and q40_hwclk() all make this adjustment. Unfortunately,
dn_dummy_hwclk(), mvme147_hwclk(), mvme16x_hwclk(), sun3_hwclk() and
sun3x_hwclk() fail to decrement tm_mon. Also m68328_hwclk() assumes
a one-based tm_mon.
Bring these platforms into line and fix read_persistent_clock() so it
works correctly on all m68k platforms.
The datasheets for the RTC devices found on the affected platforms
all confirm that the year is stored as a value in the range 0-99 and
the month is stored as a value in the range 1-12. Please refer to the
datasheets for MC146818 (Apollo), DS1643 (MVME), ICM7170 (Sun 3)
and M48T02 (Sun 3x).
Reported-by: Stan Johnson <userm57@yahoo.com>
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
2018-04-23 11:02:57 +10:00
if ( t - > tm_year < 70 )
t - > tm_year + = 100 ;
2005-04-16 15:20:36 -07:00
}
return 0 ;
}