Commit 971d9e07 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'cris-changes-for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/jesper/cris

Pull arch/chris updates from Jesper Nilsson:
 "Mostly cleanup and build fixes for CRISv32 allmodconfig

  God Jul och Gott Nytt år!"

* tag 'cris-changes-for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/jesper/cris:
  CRISv32: Remove last remnants of ETRAX_SPI_MMC_BOARD
  CRISv32: ETRAXFS: Fix recursive spinlock
  CRISv32: Select MTDRAM for axisflashmap
  CRISv32: Implement early console
  CRIS: Use KALLSYMs if available in call stack dump
  CRISv32: Fix declaration mismatch
  CRISv32: Rewrite of synchronous serial port driver
  CRIS: Update init memory handling
  CRISv32: Better handling of watchdog bite
  CRIS: Export missing function symbols
  CRIS: Export ioremap_nocache
  CRIS: Fix headers_install
  CRISv32: Add missing include for mm.h
  CRISv32: Drop obsolete file for SPI driver
parents acab1f88 8bcabff0
...@@ -30,8 +30,7 @@ ...@@ -30,8 +30,7 @@
/* Copy to userspace. This is based on the memcpy used for /* Copy to userspace. This is based on the memcpy used for
kernel-to-kernel copying; see "string.c". */ kernel-to-kernel copying; see "string.c". */
unsigned long unsigned long __copy_user(void __user *pdst, const void *psrc, unsigned long pn)
__copy_user (void __user *pdst, const void *psrc, unsigned long pn)
{ {
/* We want the parameters put in special registers. /* We want the parameters put in special registers.
Make sure the compiler is able to make something useful of this. Make sure the compiler is able to make something useful of this.
...@@ -187,13 +186,14 @@ __copy_user (void __user *pdst, const void *psrc, unsigned long pn) ...@@ -187,13 +186,14 @@ __copy_user (void __user *pdst, const void *psrc, unsigned long pn)
return retn; return retn;
} }
EXPORT_SYMBOL(__copy_user);
/* Copy from user to kernel, zeroing the bytes that were inaccessible in /* Copy from user to kernel, zeroing the bytes that were inaccessible in
userland. The return-value is the number of bytes that were userland. The return-value is the number of bytes that were
inaccessible. */ inaccessible. */
unsigned long unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
__copy_user_zeroing(void *pdst, const void __user *psrc, unsigned long pn) unsigned long pn)
{ {
/* We want the parameters put in special registers. /* We want the parameters put in special registers.
Make sure the compiler is able to make something useful of this. Make sure the compiler is able to make something useful of this.
...@@ -369,11 +369,10 @@ __copy_user_zeroing(void *pdst, const void __user *psrc, unsigned long pn) ...@@ -369,11 +369,10 @@ __copy_user_zeroing(void *pdst, const void __user *psrc, unsigned long pn)
return retn + n; return retn + n;
} }
EXPORT_SYMBOL(__copy_user_zeroing);
/* Zero userspace. */ /* Zero userspace. */
unsigned long __do_clear_user(void __user *pto, unsigned long pn)
unsigned long
__do_clear_user (void __user *pto, unsigned long pn)
{ {
/* We want the parameters put in special registers. /* We want the parameters put in special registers.
Make sure the compiler is able to make something useful of this. Make sure the compiler is able to make something useful of this.
...@@ -521,3 +520,4 @@ __do_clear_user (void __user *pto, unsigned long pn) ...@@ -521,3 +520,4 @@ __do_clear_user (void __user *pto, unsigned long pn)
return retn; return retn;
} }
EXPORT_SYMBOL(__do_clear_user);
...@@ -108,6 +108,7 @@ config ETRAX_AXISFLASHMAP ...@@ -108,6 +108,7 @@ config ETRAX_AXISFLASHMAP
select MTD_JEDECPROBE select MTD_JEDECPROBE
select MTD_BLOCK select MTD_BLOCK
select MTD_COMPLEX_MAPPINGS select MTD_COMPLEX_MAPPINGS
select MTD_MTDRAM
help help
This option enables MTD mapping of flash devices. Needed to use This option enables MTD mapping of flash devices. Needed to use
flash memories. If unsure, say Y. flash memories. If unsure, say Y.
...@@ -358,13 +359,6 @@ config ETRAX_SPI_MMC ...@@ -358,13 +359,6 @@ config ETRAX_SPI_MMC
default MMC default MMC
select SPI select SPI
select MMC_SPI select MMC_SPI
select ETRAX_SPI_MMC_BOARD
# For the parts that can't be a module (due to restrictions in
# framework elsewhere).
config ETRAX_SPI_MMC_BOARD
boolean
default n
# While the board info is MMC_SPI only, the drivers are written to be # While the board info is MMC_SPI only, the drivers are written to be
# independent of MMC_SPI, so we'll keep SPI non-dependent on the # independent of MMC_SPI, so we'll keep SPI non-dependent on the
......
...@@ -10,4 +10,3 @@ obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o ...@@ -10,4 +10,3 @@ obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o
obj-$(CONFIG_ETRAX_I2C) += i2c.o obj-$(CONFIG_ETRAX_I2C) += i2c.o
obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PCI) += pci/
obj-$(CONFIG_ETRAX_SPI_MMC_BOARD) += board_mmcspi.o
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#include <linux/init.h> #include <linux/init.h>
/* High level I2C actions */ /* High level I2C actions */
int __init i2c_init(void);
int i2c_write(unsigned char theSlave, void *data, size_t nbytes); int i2c_write(unsigned char theSlave, void *data, size_t nbytes);
int i2c_read(unsigned char theSlave, void *data, size_t nbytes); int i2c_read(unsigned char theSlave, void *data, size_t nbytes);
int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
......
/* /*
* Simple synchronous serial port driver for ETRAX FS and Artpec-3. * Simple synchronous serial port driver for ETRAX FS and ARTPEC-3.
*
* Copyright (c) 2005 Axis Communications AB
* *
* Copyright (c) 2005, 2008 Axis Communications AB
* Author: Mikael Starvik * Author: Mikael Starvik
* *
*/ */
...@@ -16,16 +15,17 @@ ...@@ -16,16 +15,17 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/init.h> #include <linux/fs.h>
#include <linux/timer.h> #include <linux/cdev.h>
#include <linux/spinlock.h> #include <linux/device.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <asm/io.h> #include <asm/io.h>
#include <dma.h> #include <mach/dma.h>
#include <pinmux.h> #include <pinmux.h>
#include <hwregs/reg_rdwr.h> #include <hwregs/reg_rdwr.h>
#include <hwregs/sser_defs.h> #include <hwregs/sser_defs.h>
#include <hwregs/timer_defs.h>
#include <hwregs/dma_defs.h> #include <hwregs/dma_defs.h>
#include <hwregs/dma.h> #include <hwregs/dma.h>
#include <hwregs/intr_vect_defs.h> #include <hwregs/intr_vect_defs.h>
...@@ -59,22 +59,23 @@ ...@@ -59,22 +59,23 @@
/* the rest of the data pointed out by Descr1 and set readp to the start */ /* the rest of the data pointed out by Descr1 and set readp to the start */
/* of Descr2 */ /* of Descr2 */
#define SYNC_SERIAL_MAJOR 125
/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */ /* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */
/* words can be handled */ /* words can be handled */
#define IN_BUFFER_SIZE 12288 #define IN_DESCR_SIZE SSP_INPUT_CHUNK_SIZE
#define IN_DESCR_SIZE 256 #define NBR_IN_DESCR (8*6)
#define NBR_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE) #define IN_BUFFER_SIZE (IN_DESCR_SIZE * NBR_IN_DESCR)
#define OUT_BUFFER_SIZE 1024*8
#define NBR_OUT_DESCR 8 #define NBR_OUT_DESCR 8
#define OUT_BUFFER_SIZE (1024 * NBR_OUT_DESCR)
#define DEFAULT_FRAME_RATE 0 #define DEFAULT_FRAME_RATE 0
#define DEFAULT_WORD_RATE 7 #define DEFAULT_WORD_RATE 7
/* To be removed when we move to pure udev. */
#define SYNC_SERIAL_MAJOR 125
/* NOTE: Enabling some debug will likely cause overrun or underrun, /* NOTE: Enabling some debug will likely cause overrun or underrun,
* especially if manual mode is use. * especially if manual mode is used.
*/ */
#define DEBUG(x) #define DEBUG(x)
#define DEBUGREAD(x) #define DEBUGREAD(x)
...@@ -85,11 +86,28 @@ ...@@ -85,11 +86,28 @@
#define DEBUGTRDMA(x) #define DEBUGTRDMA(x)
#define DEBUGOUTBUF(x) #define DEBUGOUTBUF(x)
typedef struct sync_port enum syncser_irq_setup {
{ no_irq_setup = 0,
reg_scope_instances regi_sser; dma_irq_setup = 1,
reg_scope_instances regi_dmain; manual_irq_setup = 2,
reg_scope_instances regi_dmaout; };
struct sync_port {
unsigned long regi_sser;
unsigned long regi_dmain;
unsigned long regi_dmaout;
/* Interrupt vectors. */
unsigned long dma_in_intr_vect; /* Used for DMA in. */
unsigned long dma_out_intr_vect; /* Used for DMA out. */
unsigned long syncser_intr_vect; /* Used when no DMA. */
/* DMA number for in and out. */
unsigned int dma_in_nbr;
unsigned int dma_out_nbr;
/* DMA owner. */
enum dma_owner req_dma;
char started; /* 1 if port has been started */ char started; /* 1 if port has been started */
char port_nbr; /* Port 0 or 1 */ char port_nbr; /* Port 0 or 1 */
...@@ -99,22 +117,29 @@ typedef struct sync_port ...@@ -99,22 +117,29 @@ typedef struct sync_port
char use_dma; /* 1 if port uses dma */ char use_dma; /* 1 if port uses dma */
char tr_running; char tr_running;
char init_irqs; enum syncser_irq_setup init_irqs;
int output; int output;
int input; int input;
/* Next byte to be read by application */ /* Next byte to be read by application */
volatile unsigned char *volatile readp; unsigned char *readp;
/* Next byte to be written by etrax */ /* Next byte to be written by etrax */
volatile unsigned char *volatile writep; unsigned char *writep;
unsigned int in_buffer_size; unsigned int in_buffer_size;
unsigned int in_buffer_len;
unsigned int inbufchunk; unsigned int inbufchunk;
unsigned char out_buffer[OUT_BUFFER_SIZE] __attribute__ ((aligned(32))); /* Data buffers for in and output. */
unsigned char in_buffer[IN_BUFFER_SIZE]__attribute__ ((aligned(32))); unsigned char out_buffer[OUT_BUFFER_SIZE] __aligned(32);
unsigned char flip[IN_BUFFER_SIZE] __attribute__ ((aligned(32))); unsigned char in_buffer[IN_BUFFER_SIZE] __aligned(32);
struct dma_descr_data* next_rx_desc; unsigned char flip[IN_BUFFER_SIZE] __aligned(32);
struct dma_descr_data* prev_rx_desc; struct timespec timestamp[NBR_IN_DESCR];
struct dma_descr_data *next_rx_desc;
struct dma_descr_data *prev_rx_desc;
struct timeval last_timestamp;
int read_ts_idx;
int write_ts_idx;
/* Pointer to the first available descriptor in the ring, /* Pointer to the first available descriptor in the ring,
* unless active_tr_descr == catch_tr_descr and a dma * unless active_tr_descr == catch_tr_descr and a dma
...@@ -135,114 +160,138 @@ typedef struct sync_port ...@@ -135,114 +160,138 @@ typedef struct sync_port
/* Number of bytes currently locked for being read by DMA */ /* Number of bytes currently locked for being read by DMA */
int out_buf_count; int out_buf_count;
dma_descr_data in_descr[NBR_IN_DESCR] __attribute__ ((__aligned__(16))); dma_descr_context in_context __aligned(32);
dma_descr_context in_context __attribute__ ((__aligned__(32))); dma_descr_context out_context __aligned(32);
dma_descr_data out_descr[NBR_OUT_DESCR] dma_descr_data in_descr[NBR_IN_DESCR] __aligned(16);
__attribute__ ((__aligned__(16))); dma_descr_data out_descr[NBR_OUT_DESCR] __aligned(16);
dma_descr_context out_context __attribute__ ((__aligned__(32)));
wait_queue_head_t out_wait_q; wait_queue_head_t out_wait_q;
wait_queue_head_t in_wait_q; wait_queue_head_t in_wait_q;
spinlock_t lock; spinlock_t lock;
} sync_port; };
static DEFINE_MUTEX(sync_serial_mutex); static DEFINE_MUTEX(sync_serial_mutex);
static int etrax_sync_serial_init(void); static int etrax_sync_serial_init(void);
static void initialize_port(int portnbr); static void initialize_port(int portnbr);
static inline int sync_data_avail(struct sync_port *port); static inline int sync_data_avail(struct sync_port *port);
static int sync_serial_open(struct inode *, struct file*); static int sync_serial_open(struct inode *, struct file *);
static int sync_serial_release(struct inode*, struct file*); static int sync_serial_release(struct inode *, struct file *);
static unsigned int sync_serial_poll(struct file *filp, poll_table *wait); static unsigned int sync_serial_poll(struct file *filp, poll_table *wait);
static int sync_serial_ioctl(struct file *, static long sync_serial_ioctl(struct file *file,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
static ssize_t sync_serial_write(struct file * file, const char * buf, static int sync_serial_ioctl_unlocked(struct file *file,
unsigned int cmd, unsigned long arg);
static ssize_t sync_serial_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos); size_t count, loff_t *ppos);
static ssize_t sync_serial_read(struct file *file, char *buf, static ssize_t sync_serial_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos); size_t count, loff_t *ppos);
#if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \ #if ((defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \
defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \ defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \
(defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \ (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \
defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)) defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)))
#define SYNC_SER_DMA #define SYNC_SER_DMA
#else
#define SYNC_SER_MANUAL
#endif #endif
static void send_word(sync_port* port);
static void start_dma_out(struct sync_port *port, const char *data, int count);
static void start_dma_in(sync_port* port);
#ifdef SYNC_SER_DMA #ifdef SYNC_SER_DMA
static void start_dma_out(struct sync_port *port, const char *data, int count);
static void start_dma_in(struct sync_port *port);
static irqreturn_t tr_interrupt(int irq, void *dev_id); static irqreturn_t tr_interrupt(int irq, void *dev_id);
static irqreturn_t rx_interrupt(int irq, void *dev_id); static irqreturn_t rx_interrupt(int irq, void *dev_id);
#endif #endif
#if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \
!defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \
(defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \
!defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA))
#define SYNC_SER_MANUAL
#endif
#ifdef SYNC_SER_MANUAL #ifdef SYNC_SER_MANUAL
static void send_word(struct sync_port *port);
static irqreturn_t manual_interrupt(int irq, void *dev_id); static irqreturn_t manual_interrupt(int irq, void *dev_id);
#endif #endif
#ifdef CONFIG_ETRAXFS /* ETRAX FS */ #define artpec_pinmux_alloc_fixed crisv32_pinmux_alloc_fixed
#define OUT_DMA_NBR 4 #define artpec_request_dma crisv32_request_dma
#define IN_DMA_NBR 5 #define artpec_free_dma crisv32_free_dma
#define PINMUX_SSER pinmux_sser0
#define SYNCSER_INST regi_sser0 #ifdef CONFIG_ETRAXFS
#define SYNCSER_INTR_VECT SSER0_INTR_VECT /* ETRAX FS */
#define OUT_DMA_INST regi_dma4 #define DMA_OUT_NBR0 SYNC_SER0_TX_DMA_NBR
#define IN_DMA_INST regi_dma5 #define DMA_IN_NBR0 SYNC_SER0_RX_DMA_NBR
#define DMA_OUT_INTR_VECT DMA4_INTR_VECT #define DMA_OUT_NBR1 SYNC_SER1_TX_DMA_NBR
#define DMA_IN_INTR_VECT DMA5_INTR_VECT #define DMA_IN_NBR1 SYNC_SER1_RX_DMA_NBR
#define REQ_DMA_SYNCSER dma_sser0 #define PINMUX_SSER0 pinmux_sser0
#else /* Artpec-3 */ #define PINMUX_SSER1 pinmux_sser1
#define OUT_DMA_NBR 6 #define SYNCSER_INST0 regi_sser0
#define IN_DMA_NBR 7 #define SYNCSER_INST1 regi_sser1
#define PINMUX_SSER pinmux_sser #define SYNCSER_INTR_VECT0 SSER0_INTR_VECT
#define SYNCSER_INST regi_sser #define SYNCSER_INTR_VECT1 SSER1_INTR_VECT
#define SYNCSER_INTR_VECT SSER_INTR_VECT #define OUT_DMA_INST0 regi_dma4
#define OUT_DMA_INST regi_dma6 #define IN_DMA_INST0 regi_dma5
#define IN_DMA_INST regi_dma7 #define DMA_OUT_INTR_VECT0 DMA4_INTR_VECT
#define DMA_OUT_INTR_VECT DMA6_INTR_VECT #define DMA_OUT_INTR_VECT1 DMA7_INTR_VECT
#define DMA_IN_INTR_VECT DMA7_INTR_VECT #define DMA_IN_INTR_VECT0 DMA5_INTR_VECT
#define REQ_DMA_SYNCSER dma_sser #define DMA_IN_INTR_VECT1 DMA6_INTR_VECT
#define REQ_DMA_SYNCSER0 dma_sser0
#define REQ_DMA_SYNCSER1 dma_sser1
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)
#define PORT1_DMA 1
#else
#define PORT1_DMA 0
#endif
#elif defined(CONFIG_CRIS_MACH_ARTPEC3)
/* ARTPEC-3 */
#define DMA_OUT_NBR0 SYNC_SER_TX_DMA_NBR
#define DMA_IN_NBR0 SYNC_SER_RX_DMA_NBR
#define PINMUX_SSER0 pinmux_sser
#define SYNCSER_INST0 regi_sser
#define SYNCSER_INTR_VECT0 SSER_INTR_VECT
#define OUT_DMA_INST0 regi_dma6
#define IN_DMA_INST0 regi_dma7
#define DMA_OUT_INTR_VECT0 DMA6_INTR_VECT
#define DMA_IN_INTR_VECT0 DMA7_INTR_VECT
#define REQ_DMA_SYNCSER0 dma_sser
#define REQ_DMA_SYNCSER1 dma_sser
#endif #endif
/* The ports */
static struct sync_port ports[]=
{
{
.regi_sser = SYNCSER_INST,
.regi_dmaout = OUT_DMA_INST,
.regi_dmain = IN_DMA_INST,
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)
.use_dma = 1, #define PORT0_DMA 1
#else #else
.use_dma = 0, #define PORT0_DMA 0
#endif #endif
}
#ifdef CONFIG_ETRAXFS
,
/* The ports */
static struct sync_port ports[] = {
{ {
.regi_sser = regi_sser1, .regi_sser = SYNCSER_INST0,
.regi_dmaout = regi_dma6, .regi_dmaout = OUT_DMA_INST0,
.regi_dmain = regi_dma7, .regi_dmain = IN_DMA_INST0,
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) .use_dma = PORT0_DMA,
.use_dma = 1, .dma_in_intr_vect = DMA_IN_INTR_VECT0,
#else .dma_out_intr_vect = DMA_OUT_INTR_VECT0,
.use_dma = 0, .dma_in_nbr = DMA_IN_NBR0,
#endif .dma_out_nbr = DMA_OUT_NBR0,
} .req_dma = REQ_DMA_SYNCSER0,
.syncser_intr_vect = SYNCSER_INTR_VECT0,
},
#ifdef CONFIG_ETRAXFS
{
.regi_sser = SYNCSER_INST1,
.regi_dmaout = regi_dma6,
.regi_dmain = regi_dma7,
.use_dma = PORT1_DMA,
.dma_in_intr_vect = DMA_IN_INTR_VECT1,
.dma_out_intr_vect = DMA_OUT_INTR_VECT1,
.dma_in_nbr = DMA_IN_NBR1,
.dma_out_nbr = DMA_OUT_NBR1,
.req_dma = REQ_DMA_SYNCSER1,
.syncser_intr_vect = SYNCSER_INTR_VECT1,
},
#endif #endif
}; };
#define NBR_PORTS ARRAY_SIZE(ports) #define NBR_PORTS ARRAY_SIZE(ports)
static const struct file_operations sync_serial_fops = { static const struct file_operations syncser_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.write = sync_serial_write, .write = sync_serial_write,
.read = sync_serial_read, .read = sync_serial_read,
...@@ -253,61 +302,40 @@ static const struct file_operations sync_serial_fops = { ...@@ -253,61 +302,40 @@ static const struct file_operations sync_serial_fops = {
.llseek = noop_llseek, .llseek = noop_llseek,
}; };
static int __init etrax_sync_serial_init(void) static dev_t syncser_first;
{ static int minor_count = NBR_PORTS;
ports[0].enabled = 0; #define SYNCSER_NAME "syncser"
#ifdef CONFIG_ETRAXFS static struct cdev *syncser_cdev;
ports[1].enabled = 0; static struct class *syncser_class;
#endif
if (register_chrdev(SYNC_SERIAL_MAJOR, "sync serial",
&sync_serial_fops) < 0) {
printk(KERN_WARNING
"Unable to get major for synchronous serial port\n");
return -EBUSY;
}
/* Initialize Ports */
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
if (crisv32_pinmux_alloc_fixed(PINMUX_SSER)) {
printk(KERN_WARNING
"Unable to alloc pins for synchronous serial port 0\n");
return -EIO;
}
ports[0].enabled = 1;
initialize_port(0);
#endif
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
if (crisv32_pinmux_alloc_fixed(pinmux_sser1)) {
printk(KERN_WARNING
"Unable to alloc pins for synchronous serial port 0\n");
return -EIO;
}
ports[1].enabled = 1;
initialize_port(1);
#endif
#ifdef CONFIG_ETRAXFS static void sync_serial_start_port(struct sync_port *port)
printk(KERN_INFO "ETRAX FS synchronous serial port driver\n"); {
#else reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);
printk(KERN_INFO "Artpec-3 synchronous serial port driver\n"); reg_sser_rw_tr_cfg tr_cfg =
#endif REG_RD(sser, port->regi_sser, rw_tr_cfg);
return 0; reg_sser_rw_rec_cfg rec_cfg =
REG_RD(sser, port->regi_sser, rw_rec_cfg);
cfg.en = regk_sser_yes;
tr_cfg.tr_en = regk_sser_yes;
rec_cfg.rec_en = regk_sser_yes;
REG_WR(sser, port->regi_sser, rw_cfg, cfg);
REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
port->started = 1;
} }
static void __init initialize_port(int portnbr) static void __init initialize_port(int portnbr)
{ {
int __attribute__((unused)) i;
struct sync_port *port = &ports[portnbr]; struct sync_port *port = &ports[portnbr];
reg_sser_rw_cfg cfg = {0}; reg_sser_rw_cfg cfg = { 0 };
reg_sser_rw_frm_cfg frm_cfg = {0}; reg_sser_rw_frm_cfg frm_cfg = { 0 };
reg_sser_rw_tr_cfg tr_cfg = {0}; reg_sser_rw_tr_cfg tr_cfg = { 0 };
reg_sser_rw_rec_cfg rec_cfg = {0}; reg_sser_rw_rec_cfg rec_cfg = { 0 };
DEBUG(printk(KERN_DEBUG "Init sync serial port %d\n", portnbr)); DEBUG(pr_info("Init sync serial port %d\n", portnbr));
port->port_nbr = portnbr; port->port_nbr = portnbr;
port->init_irqs = 1; port->init_irqs = no_irq_setup;
port->out_rd_ptr = port->out_buffer; port->out_rd_ptr = port->out_buffer;
port->out_buf_count = 0; port->out_buf_count = 0;
...@@ -318,10 +346,11 @@ static void __init initialize_port(int portnbr) ...@@ -318,10 +346,11 @@ static void __init initialize_port(int portnbr)
port->readp = port->flip; port->readp = port->flip;
port->writep = port->flip; port->writep = port->flip;
port->in_buffer_size = IN_BUFFER_SIZE; port->in_buffer_size = IN_BUFFER_SIZE;
port->in_buffer_len = 0;
port->inbufchunk = IN_DESCR_SIZE; port->inbufchunk = IN_DESCR_SIZE;
port->next_rx_desc = &port->in_descr[0];
port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR-1]; port->read_ts_idx = 0;
port->prev_rx_desc->eol = 1; port->write_ts_idx = 0;
init_waitqueue_head(&port->out_wait_q); init_waitqueue_head(&port->out_wait_q);
init_waitqueue_head(&port->in_wait_q); init_waitqueue_head(&port->in_wait_q);
...@@ -368,14 +397,18 @@ static void __init initialize_port(int portnbr) ...@@ -368,14 +397,18 @@ static void __init initialize_port(int portnbr)
REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
#ifdef SYNC_SER_DMA #ifdef SYNC_SER_DMA
/* Setup the descriptor ring for dma out/transmit. */ {
for (i = 0; i < NBR_OUT_DESCR; i++) { int i;
port->out_descr[i].wait = 0; /* Setup the descriptor ring for dma out/transmit. */
port->out_descr[i].intr = 1; for (i = 0; i < NBR_OUT_DESCR; i++) {
port->out_descr[i].eol = 0; dma_descr_data *descr = &port->out_descr[i];
port->out_descr[i].out_eop = 0; descr->wait = 0;
port->out_descr[i].next = descr->intr = 1;
(dma_descr_data *)virt_to_phys(&port->out_descr[i+1]); descr->eol = 0;
descr->out_eop = 0;
descr->next =
(dma_descr_data *)virt_to_phys(&descr[i+1]);
}
} }
/* Create a ring from the list. */ /* Create a ring from the list. */
...@@ -391,201 +424,116 @@ static void __init initialize_port(int portnbr) ...@@ -391,201 +424,116 @@ static void __init initialize_port(int portnbr)
static inline int sync_data_avail(struct sync_port *port) static inline int sync_data_avail(struct sync_port *port)
{ {
int avail; return port->in_buffer_len;
unsigned char *start;
unsigned char *end;
start = (unsigned char*)port->readp; /* cast away volatile */
end = (unsigned char*)port->writep; /* cast away volatile */
/* 0123456789 0123456789
* ----- - -----
* ^rp ^wp ^wp ^rp
*/
if (end >= start)
avail = end - start;
else
avail = port->in_buffer_size - (start - end);
return avail;
}
static inline int sync_data_avail_to_end(struct sync_port *port)
{
int avail;
unsigned char *start;
unsigned char *end;
start = (unsigned char*)port->readp; /* cast away volatile */
end = (unsigned char*)port->writep; /* cast away volatile */
/* 0123456789 0123456789
* ----- -----
* ^rp ^wp ^wp ^rp
*/
if (end >= start)
avail = end - start;
else
avail = port->flip + port->in_buffer_size - start;
return avail;
} }
static int sync_serial_open(struct inode *inode, struct file *file) static int sync_serial_open(struct inode *inode, struct file *file)
{ {
int ret = 0;
int dev = iminor(inode); int dev = iminor(inode);
int ret = -EBUSY; struct sync_port *port;
sync_port *port; #ifdef SYNC_SER_DMA
reg_dma_rw_cfg cfg = {.en = regk_dma_yes}; reg_dma_rw_cfg cfg = { .en = regk_dma_yes };
reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes}; reg_dma_rw_intr_mask intr_mask = { .data = regk_dma_yes };
#endif
mutex_lock(&sync_serial_mutex); DEBUG(pr_debug("Open sync serial port %d\n", dev));
DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev));
if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) {
{ DEBUG(pr_info("Invalid minor %d\n", dev));
DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev)); return -ENODEV;
ret = -ENODEV;
goto out;
} }
port = &ports[dev]; port = &ports[dev];
/* Allow open this device twice (assuming one reader and one writer) */ /* Allow open this device twice (assuming one reader and one writer) */
if (port->busy == 2) if (port->busy == 2) {
{ DEBUG(pr_info("syncser%d is busy\n", dev));
DEBUG(printk(KERN_DEBUG "Device is busy.. \n")); return -EBUSY;
goto out;
} }
mutex_lock(&sync_serial_mutex);
if (port->init_irqs) { /* Clear any stale date left in the flip buffer */
if (port->use_dma) { port->readp = port->writep = port->flip;
if (port == &ports[0]) { port->in_buffer_len = 0;
#ifdef SYNC_SER_DMA port->read_ts_idx = 0;
if (request_irq(DMA_OUT_INTR_VECT, port->write_ts_idx = 0;
tr_interrupt,
0, if (port->init_irqs != no_irq_setup) {
"synchronous serial 0 dma tr", /* Init only on first call. */
&ports[0])) { port->busy++;
printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); mutex_unlock(&sync_serial_mutex);
goto out; return 0;
} else if (request_irq(DMA_IN_INTR_VECT, }
rx_interrupt, if (port->use_dma) {
0,
"synchronous serial 1 dma rx",
&ports[0])) {
free_irq(DMA_OUT_INTR_VECT, &port[0]);
printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ");
goto out;
} else if (crisv32_request_dma(OUT_DMA_NBR,
"synchronous serial 0 dma tr",
DMA_VERBOSE_ON_ERROR,
0,
REQ_DMA_SYNCSER)) {
free_irq(DMA_OUT_INTR_VECT, &port[0]);
free_irq(DMA_IN_INTR_VECT, &port[0]);
printk(KERN_CRIT "Can't allocate sync serial port 0 TX DMA channel");
goto out;
} else if (crisv32_request_dma(IN_DMA_NBR,
"synchronous serial 0 dma rec",
DMA_VERBOSE_ON_ERROR,
0,
REQ_DMA_SYNCSER)) {
crisv32_free_dma(OUT_DMA_NBR);
free_irq(DMA_OUT_INTR_VECT, &port[0]);
free_irq(DMA_IN_INTR_VECT, &port[0]);
printk(KERN_CRIT "Can't allocate sync serial port 1 RX DMA channel");
goto out;
}
#endif
}
#ifdef CONFIG_ETRAXFS
else if (port == &ports[1]) {
#ifdef SYNC_SER_DMA #ifdef SYNC_SER_DMA
if (request_irq(DMA6_INTR_VECT, const char *tmp;
tr_interrupt, DEBUG(pr_info("Using DMA for syncser%d\n", dev));
0,
"synchronous serial 1 dma tr", tmp = dev == 0 ? "syncser0 tx" : "syncser1 tx";
&ports[1])) { if (request_irq(port->dma_out_intr_vect, tr_interrupt, 0,
printk(KERN_CRIT "Can't allocate sync serial port 1 IRQ"); tmp, port)) {
goto out; pr_err("Can't alloc syncser%d TX IRQ", dev);
} else if (request_irq(DMA7_INTR_VECT, ret = -EBUSY;
rx_interrupt, goto unlock_and_exit;
0, }
"synchronous serial 1 dma rx", if (artpec_request_dma(port->dma_out_nbr, tmp,
&ports[1])) { DMA_VERBOSE_ON_ERROR, 0, port->req_dma)) {
free_irq(DMA6_INTR_VECT, &ports[1]); free_irq(port->dma_out_intr_vect, port);
printk(KERN_CRIT "Can't allocate sync serial port 3 IRQ"); pr_err("Can't alloc syncser%d TX DMA", dev);
goto out; ret = -EBUSY;
} else if (crisv32_request_dma( goto unlock_and_exit;
SYNC_SER1_TX_DMA_NBR, }
"synchronous serial 1 dma tr", tmp = dev == 0 ? "syncser0 rx" : "syncser1 rx";
DMA_VERBOSE_ON_ERROR, if (request_irq(port->dma_in_intr_vect, rx_interrupt, 0,
0, tmp, port)) {
dma_sser1)) { artpec_free_dma(port->dma_out_nbr);
free_irq(DMA6_INTR_VECT, &ports[1]); free_irq(port->dma_out_intr_vect, port);
free_irq(DMA7_INTR_VECT, &ports[1]); pr_err("Can't alloc syncser%d RX IRQ", dev);
printk(KERN_CRIT "Can't allocate sync serial port 3 TX DMA channel"); ret = -EBUSY;
goto out; goto unlock_and_exit;
} else if (crisv32_request_dma( }
SYNC_SER1_RX_DMA_NBR, if (artpec_request_dma(port->dma_in_nbr, tmp,
"synchronous serial 3 dma rec", DMA_VERBOSE_ON_ERROR, 0, port->req_dma)) {
DMA_VERBOSE_ON_ERROR, artpec_free_dma(port->dma_out_nbr);
0, free_irq(port->dma_out_intr_vect, port);
dma_sser1)) { free_irq(port->dma_in_intr_vect, port);
crisv32_free_dma(SYNC_SER1_TX_DMA_NBR); pr_err("Can't alloc syncser%d RX DMA", dev);
free_irq(DMA6_INTR_VECT, &ports[1]); ret = -EBUSY;
free_irq(DMA7_INTR_VECT, &ports[1]); goto unlock_and_exit;
printk(KERN_CRIT "Can't allocate sync serial port 3 RX DMA channel"); }
goto out; /* Enable DMAs */
} REG_WR(dma, port->regi_dmain, rw_cfg, cfg);
#endif REG_WR(dma, port->regi_dmaout, rw_cfg, cfg);
} /* Enable DMA IRQs */
REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask);
REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask);
/* Set up wordsize = 1 for DMAs. */
DMA_WR_CMD(port->regi_dmain, regk_dma_set_w_size1);
DMA_WR_CMD(port->regi_dmaout, regk_dma_set_w_size1);
start_dma_in(port);
port->init_irqs = dma_irq_setup;
#endif #endif
/* Enable DMAs */ } else { /* !port->use_dma */
REG_WR(dma, port->regi_dmain, rw_cfg, cfg);
REG_WR(dma, port->regi_dmaout, rw_cfg, cfg);
/* Enable DMA IRQs */
REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask);
REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask);
/* Set up wordsize = 1 for DMAs. */
DMA_WR_CMD (port->regi_dmain, regk_dma_set_w_size1);
DMA_WR_CMD (port->regi_dmaout, regk_dma_set_w_size1);
start_dma_in(port);
port->init_irqs = 0;
} else { /* !port->use_dma */
#ifdef SYNC_SER_MANUAL #ifdef SYNC_SER_MANUAL
if (port == &ports[0]) { const char *tmp = dev == 0 ? "syncser0 manual irq" :
if (request_irq(SYNCSER_INTR_VECT, "syncser1 manual irq";
manual_interrupt, if (request_irq(port->syncser_intr_vect, manual_interrupt,
0, 0, tmp, port)) {
"synchronous serial manual irq", pr_err("Can't alloc syncser%d manual irq",
&ports[0])) { dev);
printk("Can't allocate sync serial manual irq"); ret = -EBUSY;
goto out; goto unlock_and_exit;
} }
} port->init_irqs = manual_irq_setup;
#ifdef CONFIG_ETRAXFS
else if (port == &ports[1]) {
if (request_irq(SSER1_INTR_VECT,
manual_interrupt,
0,
"synchronous serial manual irq",
&ports[1])) {
printk(KERN_CRIT "Can't allocate sync serial manual irq");
goto out;
}
}
#endif
port->init_irqs = 0;
#else #else
panic("sync_serial: Manual mode not supported.\n"); panic("sync_serial: Manual mode not supported\n");
#endif /* SYNC_SER_MANUAL */ #endif /* SYNC_SER_MANUAL */
} }
} /* port->init_irqs */
port->busy++; port->busy++;
ret = 0; ret = 0;
out:
unlock_and_exit:
mutex_unlock(&sync_serial_mutex); mutex_unlock(&sync_serial_mutex);
return ret; return ret;
} }
...@@ -593,18 +541,17 @@ static int sync_serial_open(struct inode *inode, struct file *file) ...@@ -593,18 +541,17 @@ static int sync_serial_open(struct inode *inode, struct file *file)
static int sync_serial_release(struct inode *inode, struct file *file) static int sync_serial_release(struct inode *inode, struct file *file)
{ {
int dev = iminor(inode); int dev = iminor(inode);
sync_port *port; struct sync_port *port;
if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) {
{ DEBUG(pr_info("Invalid minor %d\n", dev));
DEBUG(printk("Invalid minor %d\n", dev));
return -ENODEV; return -ENODEV;
} }
port = &ports[dev]; port = &ports[dev];
if (port->busy) if (port->busy)
port->busy--; port->busy--;
if (!port->busy) if (!port->busy)
/* XXX */ ; /* XXX */;
return 0; return 0;
} }
...@@ -612,21 +559,15 @@ static unsigned int sync_serial_poll(struct file *file, poll_table *wait) ...@@ -612,21 +559,15 @@ static unsigned int sync_serial_poll(struct file *file, poll_table *wait)
{ {
int dev = iminor(file_inode(file)); int dev = iminor(file_inode(file));
unsigned int mask = 0; unsigned int mask = 0;
sync_port *port; struct sync_port *port;
DEBUGPOLL( static unsigned int prev_mask = 0; ); DEBUGPOLL(
static unsigned int prev_mask;
);
port = &ports[dev]; port = &ports[dev];
if (!port->started) { if (!port->started)
reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); sync_serial_start_port(port);
reg_sser_rw_rec_cfg rec_cfg =
REG_RD(sser, port->regi_sser, rw_rec_cfg);
cfg.en = regk_sser_yes;
rec_cfg.rec_en = port->input;
REG_WR(sser, port->regi_sser, rw_cfg, cfg);
REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
port->started = 1;
}
poll_wait(file, &port->out_wait_q, wait); poll_wait(file, &port->out_wait_q, wait);
poll_wait(file, &port->in_wait_q, wait); poll_wait(file, &port->in_wait_q, wait);
...@@ -645,33 +586,175 @@ static unsigned int sync_serial_poll(struct file *file, poll_table *wait) ...@@ -645,33 +586,175 @@ static unsigned int sync_serial_poll(struct file *file, poll_table *wait)
if (port->input && sync_data_avail(port) >= port->inbufchunk) if (port->input && sync_data_avail(port) >= port->inbufchunk)
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM;
DEBUGPOLL(if (mask != prev_mask) DEBUGPOLL(
printk("sync_serial_poll: mask 0x%08X %s %s\n", mask, if (mask != prev_mask)
mask&POLLOUT?"POLLOUT":"", mask&POLLIN?"POLLIN":""); pr_info("sync_serial_poll: mask 0x%08X %s %s\n",
prev_mask = mask; mask,
); mask & POLLOUT ? "POLLOUT" : "",
mask & POLLIN ? "POLLIN" : "");
prev_mask = mask;
);
return mask; return mask;
} }
static int sync_serial_ioctl(struct file *file, static ssize_t __sync_serial_read(struct file *file,
unsigned int cmd, unsigned long arg) char __user *buf,
size_t count,
loff_t *ppos,
struct timespec *ts)
{
unsigned long flags;
int dev = MINOR(file->f_dentry->d_inode->i_rdev);
int avail;
struct sync_port *port;
unsigned char *start;
unsigned char *end;
if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) {
DEBUG(pr_info("Invalid minor %d\n", dev));
return -ENODEV;
}
port = &ports[dev];
if (!port->started)
sync_serial_start_port(port);
/* Calculate number of available bytes */
/* Save pointers to avoid that they are modified by interrupt */
spin_lock_irqsave(&port->lock, flags);
start = port->readp;
end = port->writep;
spin_unlock_irqrestore(&port->lock, flags);
while ((start == end) && !port->in_buffer_len) {
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(port->in_wait_q,
!(start == end && !port->full));
if (signal_pending(current))
return -EINTR;
spin_lock_irqsave(&port->lock, flags);
start = port->readp;
end = port->writep;
spin_unlock_irqrestore(&port->lock, flags);
}
DEBUGREAD(pr_info("R%d c %d ri %u wi %u /%u\n",
dev, count,
start - port->flip, end - port->flip,
port->in_buffer_size));
/* Lazy read, never return wrapped data. */
if (end > start)
avail = end - start;
else
avail = port->flip + port->in_buffer_size - start;
count = count > avail ? avail : count;
if (copy_to_user(buf, start, count))
return -EFAULT;
/* If timestamp requested, find timestamp of first returned byte
* and copy it.
* N.B: Applications that request timstamps MUST read data in
* chunks that are multiples of IN_DESCR_SIZE.
* Otherwise the timestamps will not be aligned to the data read.
*/
if (ts != NULL) {
int idx = port->read_ts_idx;
memcpy(ts, &port->timestamp[idx], sizeof(struct timespec));
port->read_ts_idx += count / IN_DESCR_SIZE;
if (port->read_ts_idx >= NBR_IN_DESCR)
port->read_ts_idx = 0;
}
spin_lock_irqsave(&port->lock, flags);
port->readp += count;
/* Check for wrap */
if (port->readp >= port->flip + port->in_buffer_size)
port->readp = port->flip;
port->in_buffer_len -= count;
port->full = 0;
spin_unlock_irqrestore(&port->lock, flags);
DEBUGREAD(pr_info("r %d\n", count));
return count;
}
static ssize_t sync_serial_input(struct file *file, unsigned long arg)
{
struct ssp_request req;
int count;
int ret;
/* Copy the request structure from user-mode. */
ret = copy_from_user(&req, (struct ssp_request __user *)arg,
sizeof(struct ssp_request));
if (ret) {
DEBUG(pr_info("sync_serial_input copy from user failed\n"));
return -EFAULT;
}
/* To get the timestamps aligned, make sure that 'len'
* is a multiple of IN_DESCR_SIZE.
*/
if ((req.len % IN_DESCR_SIZE) != 0) {
DEBUG(pr_info("sync_serial: req.len %x, IN_DESCR_SIZE %x\n",
req.len, IN_DESCR_SIZE));
return -EFAULT;
}
/* Do the actual read. */
/* Note that req.buf is actually a pointer to user space. */
count = __sync_serial_read(file, req.buf, req.len,
NULL, &req.ts);
if (count < 0) {
DEBUG(pr_info("sync_serial_input read failed\n"));
return count;
}
/* Copy the request back to user-mode. */
ret = copy_to_user((struct ssp_request __user *)arg, &req,
sizeof(struct ssp_request));
if (ret) {
DEBUG(pr_info("syncser input copy2user failed\n"));
return -EFAULT;
}
/* Return the number of bytes read. */
return count;
}
static int sync_serial_ioctl_unlocked(struct file *file,
unsigned int cmd, unsigned long arg)
{ {
int return_val = 0; int return_val = 0;
int dma_w_size = regk_dma_set_w_size1; int dma_w_size = regk_dma_set_w_size1;
int dev = iminor(file_inode(file)); int dev = iminor(file_inode(file));
sync_port *port; struct sync_port *port;
reg_sser_rw_tr_cfg tr_cfg; reg_sser_rw_tr_cfg tr_cfg;
reg_sser_rw_rec_cfg rec_cfg; reg_sser_rw_rec_cfg rec_cfg;
reg_sser_rw_frm_cfg frm_cfg; reg_sser_rw_frm_cfg frm_cfg;
reg_sser_rw_cfg gen_cfg; reg_sser_rw_cfg gen_cfg;
reg_sser_rw_intr_mask intr_mask; reg_sser_rw_intr_mask intr_mask;
if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) {
{ DEBUG(pr_info("Invalid minor %d\n", dev));
DEBUG(printk("Invalid minor %d\n", dev));
return -1; return -1;
} }
port = &ports[dev];
if (cmd == SSP_INPUT)
return sync_serial_input(file, arg);
port = &ports[dev];
spin_lock_irq(&port->lock); spin_lock_irq(&port->lock);
tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);
...@@ -680,11 +763,9 @@ static int sync_serial_ioctl(struct file *file, ...@@ -680,11 +763,9 @@ static int sync_serial_ioctl(struct file *file,
gen_cfg = REG_RD(sser, port->regi_sser, rw_cfg); gen_cfg = REG_RD(sser, port->regi_sser, rw_cfg);
intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);
switch(cmd) switch (cmd) {
{
case SSP_SPEED: case SSP_SPEED:
if (GET_SPEED(arg) == CODEC) if (GET_SPEED(arg) == CODEC) {
{
unsigned int freq; unsigned int freq;
gen_cfg.base_freq = regk_sser_f32; gen_cfg.base_freq = regk_sser_f32;
...@@ -701,15 +782,25 @@ static int sync_serial_ioctl(struct file *file, ...@@ -701,15 +782,25 @@ static int sync_serial_ioctl(struct file *file,
case FREQ_256kHz: case FREQ_256kHz:
gen_cfg.clk_div = 125 * gen_cfg.clk_div = 125 *
(1 << (freq - FREQ_256kHz)) - 1; (1 << (freq - FREQ_256kHz)) - 1;
break; break;
case FREQ_512kHz: case FREQ_512kHz:
gen_cfg.clk_div = 62; gen_cfg.clk_div = 62;
break; break;
case FREQ_1MHz: case FREQ_1MHz:
case FREQ_2MHz: case FREQ_2MHz:
case FREQ_4MHz: case FREQ_4MHz:
gen_cfg.clk_div = 8 * (1 << freq) - 1; gen_cfg.clk_div = 8 * (1 << freq) - 1;
break; break;
}
} else if (GET_SPEED(arg) == CODEC_f32768) {
gen_cfg.base_freq = regk_sser_f32_768;
switch (GET_FREQ(arg)) {
case FREQ_4096kHz:
gen_cfg.clk_div = 7;
break;
default:
spin_unlock_irq(&port->lock);
return -EINVAL;
} }
} else { } else {
gen_cfg.base_freq = regk_sser_f29_493; gen_cfg.base_freq = regk_sser_f29_493;
...@@ -767,62 +858,64 @@ static int sync_serial_ioctl(struct file *file, ...@@ -767,62 +858,64 @@ static int sync_serial_ioctl(struct file *file,
break; break;
case SSP_MODE: case SSP_MODE:
switch(arg) switch (arg) {
{ case MASTER_OUTPUT:
case MASTER_OUTPUT: port->output = 1;
port->output = 1; port->input = 0;
port->input = 0; frm_cfg.out_on = regk_sser_tr;
frm_cfg.out_on = regk_sser_tr; frm_cfg.frame_pin_dir = regk_sser_out;
frm_cfg.frame_pin_dir = regk_sser_out; gen_cfg.clk_dir = regk_sser_out;
gen_cfg.clk_dir = regk_sser_out; break;
break; case SLAVE_OUTPUT:
case SLAVE_OUTPUT: port->output = 1;
port->output = 1; port->input = 0;
port->input = 0; frm_cfg.frame_pin_dir = regk_sser_in;
frm_cfg.frame_pin_dir = regk_sser_in; gen_cfg.clk_dir = regk_sser_in;
gen_cfg.clk_dir = regk_sser_in; break;
break; case MASTER_INPUT:
case MASTER_INPUT: port->output = 0;
port->output = 0; port->input = 1;
port->input = 1; frm_cfg.frame_pin_dir = regk_sser_out;
frm_cfg.frame_pin_dir = regk_sser_out; frm_cfg.out_on = regk_sser_intern_tb;
frm_cfg.out_on = regk_sser_intern_tb; gen_cfg.clk_dir = regk_sser_out;
gen_cfg.clk_dir = regk_sser_out; break;
break; case SLAVE_INPUT:
case SLAVE_INPUT: port->output = 0;
port->output = 0; port->input = 1;
port->input = 1; frm_cfg.frame_pin_dir = regk_sser_in;
frm_cfg.frame_pin_dir = regk_sser_in; gen_cfg.clk_dir = regk_sser_in;
gen_cfg.clk_dir = regk_sser_in; break;
break; case MASTER_BIDIR:
case MASTER_BIDIR: port->output = 1;
port->output = 1; port->input = 1;
port->input = 1; frm_cfg.frame_pin_dir = regk_sser_out;
frm_cfg.frame_pin_dir = regk_sser_out; frm_cfg.out_on = regk_sser_intern_tb;
frm_cfg.out_on = regk_sser_intern_tb; gen_cfg.clk_dir = regk_sser_out;
gen_cfg.clk_dir = regk_sser_out; break;
break; case SLAVE_BIDIR:
case SLAVE_BIDIR: port->output = 1;
port->output = 1; port->input = 1;
port->input = 1; frm_cfg.frame_pin_dir = regk_sser_in;
frm_cfg.frame_pin_dir = regk_sser_in; gen_cfg.clk_dir = regk_sser_in;
gen_cfg.clk_dir = regk_sser_in; break;
break; default:
default: spin_unlock_irq(&port->lock);
spin_unlock_irq(&port->lock); return -EINVAL;
return -EINVAL;
} }
if (!port->use_dma || (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)) if (!port->use_dma || arg == MASTER_OUTPUT ||
arg == SLAVE_OUTPUT)
intr_mask.rdav = regk_sser_yes; intr_mask.rdav = regk_sser_yes;
break; break;
case SSP_FRAME_SYNC: case SSP_FRAME_SYNC:
if (arg & NORMAL_SYNC) { if (arg & NORMAL_SYNC) {
frm_cfg.rec_delay = 1; frm_cfg.rec_delay = 1;
frm_cfg.tr_delay = 1; frm_cfg.tr_delay = 1;
} } else if (arg & EARLY_SYNC)
else if (arg & EARLY_SYNC)
frm_cfg.rec_delay = frm_cfg.tr_delay = 0; frm_cfg.rec_delay = frm_cfg.tr_delay = 0;
else if (arg & SECOND_WORD_SYNC) { else if (arg & LATE_SYNC) {
frm_cfg.tr_delay = 2;
frm_cfg.rec_delay = 2;
} else if (arg & SECOND_WORD_SYNC) {
frm_cfg.rec_delay = 7; frm_cfg.rec_delay = 7;
frm_cfg.tr_delay = 1; frm_cfg.tr_delay = 1;
} }
...@@ -914,15 +1007,12 @@ static int sync_serial_ioctl(struct file *file, ...@@ -914,15 +1007,12 @@ static int sync_serial_ioctl(struct file *file,
frm_cfg.type = regk_sser_level; frm_cfg.type = regk_sser_level;
frm_cfg.tr_delay = 1; frm_cfg.tr_delay = 1;
frm_cfg.level = regk_sser_neg_lo; frm_cfg.level = regk_sser_neg_lo;
if (arg & SPI_SLAVE) if (arg & SPI_SLAVE) {
{
rec_cfg.clk_pol = regk_sser_neg; rec_cfg.clk_pol = regk_sser_neg;
gen_cfg.clk_dir = regk_sser_in; gen_cfg.clk_dir = regk_sser_in;
port->input = 1; port->input = 1;
port->output = 0; port->output = 0;
} } else {
else
{
gen_cfg.out_clk_pol = regk_sser_pos; gen_cfg.out_clk_pol = regk_sser_pos;
port->input = 0; port->input = 0;
port->output = 1; port->output = 1;
...@@ -965,19 +1055,19 @@ static int sync_serial_ioctl(struct file *file, ...@@ -965,19 +1055,19 @@ static int sync_serial_ioctl(struct file *file,
} }
static long sync_serial_ioctl(struct file *file, static long sync_serial_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
long ret; long ret;
mutex_lock(&sync_serial_mutex); mutex_lock(&sync_serial_mutex);
ret = sync_serial_ioctl_unlocked(file, cmd, arg); ret = sync_serial_ioctl_unlocked(file, cmd, arg);
mutex_unlock(&sync_serial_mutex); mutex_unlock(&sync_serial_mutex);
return ret; return ret;
} }
/* NOTE: sync_serial_write does not support concurrency */ /* NOTE: sync_serial_write does not support concurrency */
static ssize_t sync_serial_write(struct file *file, const char *buf, static ssize_t sync_serial_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
int dev = iminor(file_inode(file)); int dev = iminor(file_inode(file));
...@@ -993,7 +1083,7 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, ...@@ -993,7 +1083,7 @@ static ssize_t sync_serial_write(struct file *file, const char *buf,
unsigned char *buf_stop_ptr; /* Last byte + 1 */ unsigned char *buf_stop_ptr; /* Last byte + 1 */
if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) {
DEBUG(printk("Invalid minor %d\n", dev)); DEBUG(pr_info("Invalid minor %d\n", dev));
return -ENODEV; return -ENODEV;
} }
port = &ports[dev]; port = &ports[dev];
...@@ -1006,9 +1096,9 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, ...@@ -1006,9 +1096,9 @@ static ssize_t sync_serial_write(struct file *file, const char *buf,
* |_________|___________________|________________________| * |_________|___________________|________________________|
* ^ rd_ptr ^ wr_ptr * ^ rd_ptr ^ wr_ptr
*/ */
DEBUGWRITE(printk(KERN_DEBUG "W d%d c %lu a: %p c: %p\n", DEBUGWRITE(pr_info("W d%d c %u a: %p c: %p\n",
port->port_nbr, count, port->active_tr_descr, port->port_nbr, count, port->active_tr_descr,
port->catch_tr_descr)); port->catch_tr_descr));
/* Read variables that may be updated by interrupts */ /* Read variables that may be updated by interrupts */
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
...@@ -1020,7 +1110,7 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, ...@@ -1020,7 +1110,7 @@ static ssize_t sync_serial_write(struct file *file, const char *buf,
if (port->tr_running && if (port->tr_running &&
((port->use_dma && port->active_tr_descr == port->catch_tr_descr) || ((port->use_dma && port->active_tr_descr == port->catch_tr_descr) ||
out_buf_count >= OUT_BUFFER_SIZE)) { out_buf_count >= OUT_BUFFER_SIZE)) {
DEBUGWRITE(printk(KERN_DEBUG "sser%d full\n", dev)); DEBUGWRITE(pr_info("sser%d full\n", dev));
return -EAGAIN; return -EAGAIN;
} }
...@@ -1043,15 +1133,16 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, ...@@ -1043,15 +1133,16 @@ static ssize_t sync_serial_write(struct file *file, const char *buf,
if (copy_from_user(wr_ptr, buf, trunc_count)) if (copy_from_user(wr_ptr, buf, trunc_count))
return -EFAULT; return -EFAULT;
DEBUGOUTBUF(printk(KERN_DEBUG "%-4d + %-4d = %-4d %p %p %p\n", DEBUGOUTBUF(pr_info("%-4d + %-4d = %-4d %p %p %p\n",
out_buf_count, trunc_count, out_buf_count, trunc_count,
port->out_buf_count, port->out_buffer, port->out_buf_count, port->out_buffer,
wr_ptr, buf_stop_ptr)); wr_ptr, buf_stop_ptr));
/* Make sure transmitter/receiver is running */ /* Make sure transmitter/receiver is running */
if (!port->started) { if (!port->started) {
reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);
reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); reg_sser_rw_rec_cfg rec_cfg =
REG_RD(sser, port->regi_sser, rw_rec_cfg);
cfg.en = regk_sser_yes; cfg.en = regk_sser_yes;
rec_cfg.rec_en = port->input; rec_cfg.rec_en = port->input;
REG_WR(sser, port->regi_sser, rw_cfg, cfg); REG_WR(sser, port->regi_sser, rw_cfg, cfg);
...@@ -1068,8 +1159,11 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, ...@@ -1068,8 +1159,11 @@ static ssize_t sync_serial_write(struct file *file, const char *buf,
spin_lock_irqsave(&port->lock, flags); spin_lock_irqsave(&port->lock, flags);
port->out_buf_count += trunc_count; port->out_buf_count += trunc_count;
if (port->use_dma) { if (port->use_dma) {
#ifdef SYNC_SER_DMA
start_dma_out(port, wr_ptr, trunc_count); start_dma_out(port, wr_ptr, trunc_count);
#endif
} else if (!port->tr_running) { } else if (!port->tr_running) {
#ifdef SYNC_SER_MANUAL
reg_sser_rw_intr_mask intr_mask; reg_sser_rw_intr_mask intr_mask;
intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);
/* Start sender by writing data */ /* Start sender by writing data */
...@@ -1077,14 +1171,15 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, ...@@ -1077,14 +1171,15 @@ static ssize_t sync_serial_write(struct file *file, const char *buf,
/* and enable transmitter ready IRQ */ /* and enable transmitter ready IRQ */
intr_mask.trdy = 1; intr_mask.trdy = 1;
REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);
#endif
} }
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
/* Exit if non blocking */ /* Exit if non blocking */
if (file->f_flags & O_NONBLOCK) { if (file->f_flags & O_NONBLOCK) {
DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu %08x\n", DEBUGWRITE(pr_info("w d%d c %u %08x\n",
port->port_nbr, trunc_count, port->port_nbr, trunc_count,
REG_RD_INT(dma, port->regi_dmaout, r_intr))); REG_RD_INT(dma, port->regi_dmaout, r_intr)));
return trunc_count; return trunc_count;
} }
...@@ -1094,105 +1189,32 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, ...@@ -1094,105 +1189,32 @@ static ssize_t sync_serial_write(struct file *file, const char *buf,
if (signal_pending(current)) if (signal_pending(current))
return -EINTR; return -EINTR;
DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu\n", DEBUGWRITE(pr_info("w d%d c %u\n", port->port_nbr, trunc_count));
port->port_nbr, trunc_count));
return trunc_count; return trunc_count;
} }
static ssize_t sync_serial_read(struct file * file, char * buf, static ssize_t sync_serial_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
int dev = iminor(file_inode(file)); return __sync_serial_read(file, buf, count, ppos, NULL);
int avail;
sync_port *port;
unsigned char* start;
unsigned char* end;
unsigned long flags;
if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)
{
DEBUG(printk("Invalid minor %d\n", dev));
return -ENODEV;
}
port = &ports[dev];
DEBUGREAD(printk("R%d c %d ri %lu wi %lu /%lu\n", dev, count, port->readp - port->flip, port->writep - port->flip, port->in_buffer_size));
if (!port->started)
{
reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);
reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);
reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg);
cfg.en = regk_sser_yes;
tr_cfg.tr_en = regk_sser_yes;
rec_cfg.rec_en = regk_sser_yes;
REG_WR(sser, port->regi_sser, rw_cfg, cfg);
REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);
port->started = 1;
}
/* Calculate number of available bytes */
/* Save pointers to avoid that they are modified by interrupt */
spin_lock_irqsave(&port->lock, flags);
start = (unsigned char*)port->readp; /* cast away volatile */
end = (unsigned char*)port->writep; /* cast away volatile */
spin_unlock_irqrestore(&port->lock, flags);
while ((start == end) && !port->full) /* No data */
{
DEBUGREAD(printk(KERN_DEBUG "&"));
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(port->in_wait_q,
!(start == end && !port->full));
if (signal_pending(current))
return -EINTR;
spin_lock_irqsave(&port->lock, flags);
start = (unsigned char*)port->readp; /* cast away volatile */
end = (unsigned char*)port->writep; /* cast away volatile */
spin_unlock_irqrestore(&port->lock, flags);
}
/* Lazy read, never return wrapped data. */
if (port->full)
avail = port->in_buffer_size;
else if (end > start)
avail = end - start;
else
avail = port->flip + port->in_buffer_size - start;
count = count > avail ? avail : count;
if (copy_to_user(buf, start, count))
return -EFAULT;
/* Disable interrupts while updating readp */
spin_lock_irqsave(&port->lock, flags);
port->readp += count;
if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */
port->readp = port->flip;
port->full = 0;
spin_unlock_irqrestore(&port->lock, flags);
DEBUGREAD(printk("r %d\n", count));
return count;
} }
static void send_word(sync_port* port) #ifdef SYNC_SER_MANUAL
static void send_word(struct sync_port *port)
{ {
reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);
reg_sser_rw_tr_data tr_data = {0}; reg_sser_rw_tr_data tr_data = {0};
switch(tr_cfg.sample_size) switch (tr_cfg.sample_size) {
case 8:
port->out_buf_count--;
tr_data.data = *port->out_rd_ptr++;
REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)
port->out_rd_ptr = port->out_buffer;
break;
case 12:
{ {
case 8:
port->out_buf_count--;
tr_data.data = *port->out_rd_ptr++;
REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)
port->out_rd_ptr = port->out_buffer;
break;
case 12:
{
int data = (*port->out_rd_ptr++) << 8; int data = (*port->out_rd_ptr++) << 8;
data |= *port->out_rd_ptr++; data |= *port->out_rd_ptr++;
port->out_buf_count -= 2; port->out_buf_count -= 2;
...@@ -1200,8 +1222,8 @@ static void send_word(sync_port* port) ...@@ -1200,8 +1222,8 @@ static void send_word(sync_port* port)
REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);
if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)
port->out_rd_ptr = port->out_buffer; port->out_rd_ptr = port->out_buffer;
break;
} }
break;
case 16: case 16:
port->out_buf_count -= 2; port->out_buf_count -= 2;
tr_data.data = *(unsigned short *)port->out_rd_ptr; tr_data.data = *(unsigned short *)port->out_rd_ptr;
...@@ -1233,27 +1255,28 @@ static void send_word(sync_port* port) ...@@ -1233,27 +1255,28 @@ static void send_word(sync_port* port)
break; break;
} }
} }
#endif
static void start_dma_out(struct sync_port *port, #ifdef SYNC_SER_DMA
const char *data, int count) static void start_dma_out(struct sync_port *port, const char *data, int count)
{ {
port->active_tr_descr->buf = (char *) virt_to_phys((char *) data); port->active_tr_descr->buf = (char *)virt_to_phys((char *)data);
port->active_tr_descr->after = port->active_tr_descr->buf + count; port->active_tr_descr->after = port->active_tr_descr->buf + count;
port->active_tr_descr->intr = 1; port->active_tr_descr->intr = 1;
port->active_tr_descr->eol = 1; port->active_tr_descr->eol = 1;
port->prev_tr_descr->eol = 0; port->prev_tr_descr->eol = 0;
DEBUGTRDMA(printk(KERN_DEBUG "Inserting eolr:%p eol@:%p\n", DEBUGTRDMA(pr_info("Inserting eolr:%p eol@:%p\n",
port->prev_tr_descr, port->active_tr_descr)); port->prev_tr_descr, port->active_tr_descr));
port->prev_tr_descr = port->active_tr_descr; port->prev_tr_descr = port->active_tr_descr;
port->active_tr_descr = phys_to_virt((int) port->active_tr_descr->next); port->active_tr_descr = phys_to_virt((int)port->active_tr_descr->next);
if (!port->tr_running) { if (!port->tr_running) {
reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser,
rw_tr_cfg); rw_tr_cfg);
port->out_context.next = 0; port->out_context.next = NULL;
port->out_context.saved_data = port->out_context.saved_data =
(dma_descr_data *)virt_to_phys(port->prev_tr_descr); (dma_descr_data *)virt_to_phys(port->prev_tr_descr);
port->out_context.saved_data_buf = port->prev_tr_descr->buf; port->out_context.saved_data_buf = port->prev_tr_descr->buf;
...@@ -1263,57 +1286,58 @@ static void start_dma_out(struct sync_port *port, ...@@ -1263,57 +1286,58 @@ static void start_dma_out(struct sync_port *port,
tr_cfg.tr_en = regk_sser_yes; tr_cfg.tr_en = regk_sser_yes;
REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);
DEBUGTRDMA(printk(KERN_DEBUG "dma s\n");); DEBUGTRDMA(pr_info(KERN_INFO "dma s\n"););
} else { } else {
DMA_CONTINUE_DATA(port->regi_dmaout); DMA_CONTINUE_DATA(port->regi_dmaout);
DEBUGTRDMA(printk(KERN_DEBUG "dma c\n");); DEBUGTRDMA(pr_info("dma c\n"););
} }
port->tr_running = 1; port->tr_running = 1;
} }
static void start_dma_in(sync_port *port) static void start_dma_in(struct sync_port *port)
{ {
int i; int i;
char *buf; char *buf;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
port->writep = port->flip; port->writep = port->flip;
spin_unlock_irqrestore(&port->lock, flags);
if (port->writep > port->flip + port->in_buffer_size) { buf = (char *)virt_to_phys(port->in_buffer);
panic("Offset too large in sync serial driver\n");
return;
}
buf = (char*)virt_to_phys(port->in_buffer);
for (i = 0; i < NBR_IN_DESCR; i++) { for (i = 0; i < NBR_IN_DESCR; i++) {
port->in_descr[i].buf = buf; port->in_descr[i].buf = buf;
port->in_descr[i].after = buf + port->inbufchunk; port->in_descr[i].after = buf + port->inbufchunk;
port->in_descr[i].intr = 1; port->in_descr[i].intr = 1;
port->in_descr[i].next = (dma_descr_data*)virt_to_phys(&port->in_descr[i+1]); port->in_descr[i].next =
(dma_descr_data *)virt_to_phys(&port->in_descr[i+1]);
port->in_descr[i].buf = buf; port->in_descr[i].buf = buf;
buf += port->inbufchunk; buf += port->inbufchunk;
} }
/* Link the last descriptor to the first */ /* Link the last descriptor to the first */
port->in_descr[i-1].next = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); port->in_descr[i-1].next =
(dma_descr_data *)virt_to_phys(&port->in_descr[0]);
port->in_descr[i-1].eol = regk_sser_yes; port->in_descr[i-1].eol = regk_sser_yes;
port->next_rx_desc = &port->in_descr[0]; port->next_rx_desc = &port->in_descr[0];
port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR - 1]; port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR - 1];
port->in_context.saved_data = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); port->in_context.saved_data =
(dma_descr_data *)virt_to_phys(&port->in_descr[0]);
port->in_context.saved_data_buf = port->in_descr[0].buf; port->in_context.saved_data_buf = port->in_descr[0].buf;
DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context)); DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context));
} }
#ifdef SYNC_SER_DMA
static irqreturn_t tr_interrupt(int irq, void *dev_id) static irqreturn_t tr_interrupt(int irq, void *dev_id)
{ {
reg_dma_r_masked_intr masked; reg_dma_r_masked_intr masked;
reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes}; reg_dma_rw_ack_intr ack_intr = { .data = regk_dma_yes };
reg_dma_rw_stat stat; reg_dma_rw_stat stat;
int i; int i;
int found = 0; int found = 0;
int stop_sser = 0; int stop_sser = 0;
for (i = 0; i < NBR_PORTS; i++) { for (i = 0; i < NBR_PORTS; i++) {
sync_port *port = &ports[i]; struct sync_port *port = &ports[i];
if (!port->enabled || !port->use_dma) if (!port->enabled || !port->use_dma)
continue; continue;
/* IRQ active for the port? */ /* IRQ active for the port? */
...@@ -1338,19 +1362,20 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) ...@@ -1338,19 +1362,20 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id)
int sent; int sent;
sent = port->catch_tr_descr->after - sent = port->catch_tr_descr->after -
port->catch_tr_descr->buf; port->catch_tr_descr->buf;
DEBUGTXINT(printk(KERN_DEBUG "%-4d - %-4d = %-4d\t" DEBUGTXINT(pr_info("%-4d - %-4d = %-4d\t"
"in descr %p (ac: %p)\n", "in descr %p (ac: %p)\n",
port->out_buf_count, sent, port->out_buf_count, sent,
port->out_buf_count - sent, port->out_buf_count - sent,
port->catch_tr_descr, port->catch_tr_descr,
port->active_tr_descr);); port->active_tr_descr););
port->out_buf_count -= sent; port->out_buf_count -= sent;
port->catch_tr_descr = port->catch_tr_descr =
phys_to_virt((int) port->catch_tr_descr->next); phys_to_virt((int) port->catch_tr_descr->next);
port->out_rd_ptr = port->out_rd_ptr =
phys_to_virt((int) port->catch_tr_descr->buf); phys_to_virt((int) port->catch_tr_descr->buf);
} else { } else {
int i, sent; reg_sser_rw_tr_cfg tr_cfg;
int j, sent;
/* EOL handler. /* EOL handler.
* Note that if an EOL was encountered during the irq * Note that if an EOL was encountered during the irq
* locked section of sync_ser_write the DMA will be * locked section of sync_ser_write the DMA will be
...@@ -1358,11 +1383,11 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) ...@@ -1358,11 +1383,11 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id)
* The remaining descriptors will be traversed by * The remaining descriptors will be traversed by
* the descriptor interrupts as usual. * the descriptor interrupts as usual.
*/ */
i = 0; j = 0;
while (!port->catch_tr_descr->eol) { while (!port->catch_tr_descr->eol) {
sent = port->catch_tr_descr->after - sent = port->catch_tr_descr->after -
port->catch_tr_descr->buf; port->catch_tr_descr->buf;
DEBUGOUTBUF(printk(KERN_DEBUG DEBUGOUTBUF(pr_info(
"traversing descr %p -%d (%d)\n", "traversing descr %p -%d (%d)\n",
port->catch_tr_descr, port->catch_tr_descr,
sent, sent,
...@@ -1370,16 +1395,15 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) ...@@ -1370,16 +1395,15 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id)
port->out_buf_count -= sent; port->out_buf_count -= sent;
port->catch_tr_descr = phys_to_virt( port->catch_tr_descr = phys_to_virt(
(int)port->catch_tr_descr->next); (int)port->catch_tr_descr->next);
i++; j++;
if (i >= NBR_OUT_DESCR) { if (j >= NBR_OUT_DESCR) {
/* TODO: Reset and recover */ /* TODO: Reset and recover */
panic("sync_serial: missing eol"); panic("sync_serial: missing eol");
} }
} }
sent = port->catch_tr_descr->after - sent = port->catch_tr_descr->after -
port->catch_tr_descr->buf; port->catch_tr_descr->buf;
DEBUGOUTBUF(printk(KERN_DEBUG DEBUGOUTBUF(pr_info("eol at descr %p -%d (%d)\n",
"eol at descr %p -%d (%d)\n",
port->catch_tr_descr, port->catch_tr_descr,
sent, sent,
port->out_buf_count)); port->out_buf_count));
...@@ -1394,15 +1418,13 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) ...@@ -1394,15 +1418,13 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id)
OUT_BUFFER_SIZE) OUT_BUFFER_SIZE)
port->out_rd_ptr = port->out_buffer; port->out_rd_ptr = port->out_buffer;
reg_sser_rw_tr_cfg tr_cfg = tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);
REG_RD(sser, port->regi_sser, rw_tr_cfg); DEBUGTXINT(pr_info(
DEBUGTXINT(printk(KERN_DEBUG
"tr_int DMA stop %d, set catch @ %p\n", "tr_int DMA stop %d, set catch @ %p\n",
port->out_buf_count, port->out_buf_count,
port->active_tr_descr)); port->active_tr_descr));
if (port->out_buf_count != 0) if (port->out_buf_count != 0)
printk(KERN_CRIT "sync_ser: buffer not " pr_err("sync_ser: buf not empty after eol\n");
"empty after eol.\n");
port->catch_tr_descr = port->active_tr_descr; port->catch_tr_descr = port->active_tr_descr;
port->tr_running = 0; port->tr_running = 0;
tr_cfg.tr_en = regk_sser_no; tr_cfg.tr_en = regk_sser_no;
...@@ -1414,62 +1436,79 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) ...@@ -1414,62 +1436,79 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id)
return IRQ_RETVAL(found); return IRQ_RETVAL(found);
} /* tr_interrupt */ } /* tr_interrupt */
static inline void handle_rx_packet(struct sync_port *port)
{
int idx;
reg_dma_rw_ack_intr ack_intr = { .data = regk_dma_yes };
unsigned long flags;
DEBUGRXINT(pr_info(KERN_INFO "!"));
spin_lock_irqsave(&port->lock, flags);
/* If we overrun the user experience is crap regardless if we
* drop new or old data. Its much easier to get it right when
* dropping new data so lets do that.
*/
if ((port->writep + port->inbufchunk <=
port->flip + port->in_buffer_size) &&
(port->in_buffer_len + port->inbufchunk < IN_BUFFER_SIZE)) {
memcpy(port->writep,
phys_to_virt((unsigned)port->next_rx_desc->buf),
port->inbufchunk);
port->writep += port->inbufchunk;
if (port->writep >= port->flip + port->in_buffer_size)
port->writep = port->flip;
/* Timestamp the new data chunk. */
if (port->write_ts_idx == NBR_IN_DESCR)
port->write_ts_idx = 0;
idx = port->write_ts_idx++;
do_posix_clock_monotonic_gettime(&port->timestamp[idx]);
port->in_buffer_len += port->inbufchunk;
}
spin_unlock_irqrestore(&port->lock, flags);
port->next_rx_desc->eol = 1;
port->prev_rx_desc->eol = 0;
/* Cache bug workaround */
flush_dma_descr(port->prev_rx_desc, 0);
port->prev_rx_desc = port->next_rx_desc;
port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next);
/* Cache bug workaround */
flush_dma_descr(port->prev_rx_desc, 1);
/* wake up the waiting process */
wake_up_interruptible(&port->in_wait_q);
DMA_CONTINUE(port->regi_dmain);
REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr);
}
static irqreturn_t rx_interrupt(int irq, void *dev_id) static irqreturn_t rx_interrupt(int irq, void *dev_id)
{ {
reg_dma_r_masked_intr masked; reg_dma_r_masked_intr masked;
reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes};
int i; int i;
int found = 0; int found = 0;
for (i = 0; i < NBR_PORTS; i++) DEBUG(pr_info("rx_interrupt\n"));
{
sync_port *port = &ports[i]; for (i = 0; i < NBR_PORTS; i++) {
struct sync_port *port = &ports[i];
if (!port->enabled || !port->use_dma ) if (!port->enabled || !port->use_dma)
continue; continue;
masked = REG_RD(dma, port->regi_dmain, r_masked_intr); masked = REG_RD(dma, port->regi_dmain, r_masked_intr);
if (masked.data) /* Descriptor interrupt */ if (!masked.data)
{ continue;
found = 1;
while (REG_RD(dma, port->regi_dmain, rw_data) !=
virt_to_phys(port->next_rx_desc)) {
DEBUGRXINT(printk(KERN_DEBUG "!"));
if (port->writep + port->inbufchunk > port->flip + port->in_buffer_size) {
int first_size = port->flip + port->in_buffer_size - port->writep;
memcpy((char*)port->writep, phys_to_virt((unsigned)port->next_rx_desc->buf), first_size);
memcpy(port->flip, phys_to_virt((unsigned)port->next_rx_desc->buf+first_size), port->inbufchunk - first_size);
port->writep = port->flip + port->inbufchunk - first_size;
} else {
memcpy((char*)port->writep,
phys_to_virt((unsigned)port->next_rx_desc->buf),
port->inbufchunk);
port->writep += port->inbufchunk;
if (port->writep >= port->flip + port->in_buffer_size)
port->writep = port->flip;
}
if (port->writep == port->readp)
{
port->full = 1;
}
port->next_rx_desc->eol = 1;
port->prev_rx_desc->eol = 0;
/* Cache bug workaround */
flush_dma_descr(port->prev_rx_desc, 0);
port->prev_rx_desc = port->next_rx_desc;
port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next);
/* Cache bug workaround */
flush_dma_descr(port->prev_rx_desc, 1);
/* wake up the waiting process */
wake_up_interruptible(&port->in_wait_q);
DMA_CONTINUE(port->regi_dmain);
REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr);
} /* Descriptor interrupt */
} found = 1;
while (REG_RD(dma, port->regi_dmain, rw_data) !=
virt_to_phys(port->next_rx_desc))
handle_rx_packet(port);
} }
return IRQ_RETVAL(found); return IRQ_RETVAL(found);
} /* rx_interrupt */ } /* rx_interrupt */
...@@ -1478,75 +1517,83 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id) ...@@ -1478,75 +1517,83 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id)
#ifdef SYNC_SER_MANUAL #ifdef SYNC_SER_MANUAL
static irqreturn_t manual_interrupt(int irq, void *dev_id) static irqreturn_t manual_interrupt(int irq, void *dev_id)
{ {
unsigned long flags;
int i; int i;
int found = 0; int found = 0;
reg_sser_r_masked_intr masked; reg_sser_r_masked_intr masked;
for (i = 0; i < NBR_PORTS; i++) for (i = 0; i < NBR_PORTS; i++) {
{ struct sync_port *port = &ports[i];
sync_port *port = &ports[i];
if (!port->enabled || port->use_dma) if (!port->enabled || port->use_dma)
{
continue; continue;
}
masked = REG_RD(sser, port->regi_sser, r_masked_intr); masked = REG_RD(sser, port->regi_sser, r_masked_intr);
if (masked.rdav) /* Data received? */ /* Data received? */
{ if (masked.rdav) {
reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); reg_sser_rw_rec_cfg rec_cfg =
reg_sser_r_rec_data data = REG_RD(sser, port->regi_sser, r_rec_data); REG_RD(sser, port->regi_sser, rw_rec_cfg);
reg_sser_r_rec_data data = REG_RD(sser,
port->regi_sser, r_rec_data);
found = 1; found = 1;
/* Read data */ /* Read data */
switch(rec_cfg.sample_size) spin_lock_irqsave(&port->lock, flags);
{ switch (rec_cfg.sample_size) {
case 8: case 8:
*port->writep++ = data.data & 0xff; *port->writep++ = data.data & 0xff;
break; break;
case 12: case 12:
*port->writep = (data.data & 0x0ff0) >> 4; *port->writep = (data.data & 0x0ff0) >> 4;
*(port->writep + 1) = data.data & 0x0f; *(port->writep + 1) = data.data & 0x0f;
port->writep+=2; port->writep += 2;
break; break;
case 16: case 16:
*(unsigned short*)port->writep = data.data; *(unsigned short *)port->writep = data.data;
port->writep+=2; port->writep += 2;
break; break;
case 24: case 24:
*(unsigned int*)port->writep = data.data; *(unsigned int *)port->writep = data.data;
port->writep+=3; port->writep += 3;
break; break;
case 32: case 32:
*(unsigned int*)port->writep = data.data; *(unsigned int *)port->writep = data.data;
port->writep+=4; port->writep += 4;
break; break;
} }
if (port->writep >= port->flip + port->in_buffer_size) /* Wrap? */ /* Wrap? */
if (port->writep >= port->flip + port->in_buffer_size)
port->writep = port->flip; port->writep = port->flip;
if (port->writep == port->readp) { if (port->writep == port->readp) {
/* receive buffer overrun, discard oldest data /* Receive buf overrun, discard oldest data */
*/
port->readp++; port->readp++;
if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */ /* Wrap? */
if (port->readp >= port->flip +
port->in_buffer_size)
port->readp = port->flip; port->readp = port->flip;
} }
spin_unlock_irqrestore(&port->lock, flags);
if (sync_data_avail(port) >= port->inbufchunk) if (sync_data_avail(port) >= port->inbufchunk)
wake_up_interruptible(&port->in_wait_q); /* Wake up application */ /* Wake up application */
wake_up_interruptible(&port->in_wait_q);
} }
if (masked.trdy) /* Transmitter ready? */ /* Transmitter ready? */
{ if (masked.trdy) {
found = 1; found = 1;
if (port->out_buf_count > 0) /* More data to send */ /* More data to send */
if (port->out_buf_count > 0)
send_word(port); send_word(port);
else /* transmission finished */ else {
{ /* Transmission finished */
reg_sser_rw_intr_mask intr_mask; reg_sser_rw_intr_mask intr_mask;
intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); intr_mask = REG_RD(sser, port->regi_sser,
rw_intr_mask);
intr_mask.trdy = 0; intr_mask.trdy = 0;
REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); REG_WR(sser, port->regi_sser,
wake_up_interruptible(&port->out_wait_q); /* Wake up application */ rw_intr_mask, intr_mask);
/* Wake up application */
wake_up_interruptible(&port->out_wait_q);
} }
} }
} }
...@@ -1554,4 +1601,109 @@ static irqreturn_t manual_interrupt(int irq, void *dev_id) ...@@ -1554,4 +1601,109 @@ static irqreturn_t manual_interrupt(int irq, void *dev_id)
} }
#endif #endif
static int __init etrax_sync_serial_init(void)
{
#if 1
/* This code will be removed when we move to udev for all devices. */
syncser_first = MKDEV(SYNC_SERIAL_MAJOR, 0);
if (register_chrdev_region(syncser_first, minor_count, SYNCSER_NAME)) {
pr_err("Failed to register major %d\n", SYNC_SERIAL_MAJOR);
return -1;
}
#else
/* Allocate dynamic major number. */
if (alloc_chrdev_region(&syncser_first, 0, minor_count, SYNCSER_NAME)) {
pr_err("Failed to allocate character device region\n");
return -1;
}
#endif
syncser_cdev = cdev_alloc();
if (!syncser_cdev) {
pr_err("Failed to allocate cdev for syncser\n");
unregister_chrdev_region(syncser_first, minor_count);
return -1;
}
cdev_init(syncser_cdev, &syncser_fops);
/* Create a sysfs class for syncser */
syncser_class = class_create(THIS_MODULE, "syncser_class");
/* Initialize Ports */
#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)
if (artpec_pinmux_alloc_fixed(PINMUX_SSER0)) {
pr_warn("Unable to alloc pins for synchronous serial port 0\n");
unregister_chrdev_region(syncser_first, minor_count);
return -EIO;
}
initialize_port(0);
ports[0].enabled = 1;
/* Register with sysfs so udev can pick it up. */
device_create(syncser_class, NULL, syncser_first, NULL,
"%s%d", SYNCSER_NAME, 0);
#endif
#if defined(CONFIG_ETRAXFS) && defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
if (artpec_pinmux_alloc_fixed(PINMUX_SSER1)) {
pr_warn("Unable to alloc pins for synchronous serial port 1\n");
unregister_chrdev_region(syncser_first, minor_count);
class_destroy(syncser_class);
return -EIO;
}
initialize_port(1);
ports[1].enabled = 1;
/* Register with sysfs so udev can pick it up. */
device_create(syncser_class, NULL, syncser_first, NULL,
"%s%d", SYNCSER_NAME, 0);
#endif
/* Add it to system */
if (cdev_add(syncser_cdev, syncser_first, minor_count) < 0) {
pr_err("Failed to add syncser as char device\n");
device_destroy(syncser_class, syncser_first);
class_destroy(syncser_class);
cdev_del(syncser_cdev);
unregister_chrdev_region(syncser_first, minor_count);
return -1;
}
pr_info("ARTPEC synchronous serial port (%s: %d, %d)\n",
SYNCSER_NAME, MAJOR(syncser_first), MINOR(syncser_first));
return 0;
}
static void __exit etrax_sync_serial_exit(void)
{
int i;
device_destroy(syncser_class, syncser_first);
class_destroy(syncser_class);
if (syncser_cdev) {
cdev_del(syncser_cdev);
unregister_chrdev_region(syncser_first, minor_count);
}
for (i = 0; i < NBR_PORTS; i++) {
struct sync_port *port = &ports[i];
if (port->init_irqs == dma_irq_setup) {
/* Free dma irqs and dma channels. */
#ifdef SYNC_SER_DMA
artpec_free_dma(port->dma_in_nbr);
artpec_free_dma(port->dma_out_nbr);
free_irq(port->dma_out_intr_vect, port);
free_irq(port->dma_in_intr_vect, port);
#endif
} else if (port->init_irqs == manual_irq_setup) {
/* Free manual irq. */
free_irq(port->syncser_intr_vect, port);
}
}
pr_info("ARTPEC synchronous serial port unregistered\n");
}
module_init(etrax_sync_serial_init); module_init(etrax_sync_serial_init);
module_exit(etrax_sync_serial_exit);
MODULE_LICENSE("GPL");
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
*/ */
#include <linux/console.h> #include <linux/console.h>
#include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/string.h>
#include <hwregs/reg_rdwr.h> #include <hwregs/reg_rdwr.h>
#include <hwregs/reg_map.h> #include <hwregs/reg_map.h>
#include <hwregs/ser_defs.h> #include <hwregs/ser_defs.h>
...@@ -65,6 +67,7 @@ struct dbg_port ports[] = ...@@ -65,6 +67,7 @@ struct dbg_port ports[] =
}, },
#endif #endif
}; };
static struct dbg_port *port = static struct dbg_port *port =
#if defined(CONFIG_ETRAX_DEBUG_PORT0) #if defined(CONFIG_ETRAX_DEBUG_PORT0)
&ports[0]; &ports[0];
...@@ -97,14 +100,19 @@ static struct dbg_port *kgdb_port = ...@@ -97,14 +100,19 @@ static struct dbg_port *kgdb_port =
#endif #endif
#endif #endif
static void static void start_port(struct dbg_port *p)
start_port(struct dbg_port* p)
{ {
if (!p) /* Set up serial port registers */
return; reg_ser_rw_tr_ctrl tr_ctrl = {0};
reg_ser_rw_tr_dma_en tr_dma_en = {0};
if (p->started) reg_ser_rw_rec_ctrl rec_ctrl = {0};
reg_ser_rw_tr_baud_div tr_baud_div = {0};
reg_ser_rw_rec_baud_div rec_baud_div = {0};
if (!p || p->started)
return; return;
p->started = 1; p->started = 1;
if (p->nbr == 1) if (p->nbr == 1)
...@@ -118,36 +126,24 @@ start_port(struct dbg_port* p) ...@@ -118,36 +126,24 @@ start_port(struct dbg_port* p)
crisv32_pinmux_alloc_fixed(pinmux_ser4); crisv32_pinmux_alloc_fixed(pinmux_ser4);
#endif #endif
/* Set up serial port registers */
reg_ser_rw_tr_ctrl tr_ctrl = {0};
reg_ser_rw_tr_dma_en tr_dma_en = {0};
reg_ser_rw_rec_ctrl rec_ctrl = {0};
reg_ser_rw_tr_baud_div tr_baud_div = {0};
reg_ser_rw_rec_baud_div rec_baud_div = {0};
tr_ctrl.base_freq = rec_ctrl.base_freq = regk_ser_f29_493; tr_ctrl.base_freq = rec_ctrl.base_freq = regk_ser_f29_493;
tr_dma_en.en = rec_ctrl.dma_mode = regk_ser_no; tr_dma_en.en = rec_ctrl.dma_mode = regk_ser_no;
tr_baud_div.div = rec_baud_div.div = 29493000 / p->baudrate / 8; tr_baud_div.div = rec_baud_div.div = 29493000 / p->baudrate / 8;
tr_ctrl.en = rec_ctrl.en = 1; tr_ctrl.en = rec_ctrl.en = 1;
if (p->parity == 'O') if (p->parity == 'O') {
{
tr_ctrl.par_en = regk_ser_yes; tr_ctrl.par_en = regk_ser_yes;
tr_ctrl.par = regk_ser_odd; tr_ctrl.par = regk_ser_odd;
rec_ctrl.par_en = regk_ser_yes; rec_ctrl.par_en = regk_ser_yes;
rec_ctrl.par = regk_ser_odd; rec_ctrl.par = regk_ser_odd;
} } else if (p->parity == 'E') {
else if (p->parity == 'E')
{
tr_ctrl.par_en = regk_ser_yes; tr_ctrl.par_en = regk_ser_yes;
tr_ctrl.par = regk_ser_even; tr_ctrl.par = regk_ser_even;
rec_ctrl.par_en = regk_ser_yes; rec_ctrl.par_en = regk_ser_yes;
rec_ctrl.par = regk_ser_odd; rec_ctrl.par = regk_ser_odd;
} }
if (p->bits == 7) if (p->bits == 7) {
{
tr_ctrl.data_bits = regk_ser_bits7; tr_ctrl.data_bits = regk_ser_bits7;
rec_ctrl.data_bits = regk_ser_bits7; rec_ctrl.data_bits = regk_ser_bits7;
} }
...@@ -161,8 +157,7 @@ start_port(struct dbg_port* p) ...@@ -161,8 +157,7 @@ start_port(struct dbg_port* p)
#ifdef CONFIG_ETRAX_KGDB #ifdef CONFIG_ETRAX_KGDB
/* Use polling to get a single character from the kernel debug port */ /* Use polling to get a single character from the kernel debug port */
int int getDebugChar(void)
getDebugChar(void)
{ {
reg_ser_rs_stat_din stat; reg_ser_rs_stat_din stat;
reg_ser_rw_ack_intr ack_intr = { 0 }; reg_ser_rw_ack_intr ack_intr = { 0 };
...@@ -179,8 +174,7 @@ getDebugChar(void) ...@@ -179,8 +174,7 @@ getDebugChar(void)
} }
/* Use polling to put a single character to the kernel debug port */ /* Use polling to put a single character to the kernel debug port */
void void putDebugChar(int val)
putDebugChar(int val)
{ {
reg_ser_r_stat_din stat; reg_ser_r_stat_din stat;
do { do {
...@@ -190,12 +184,48 @@ putDebugChar(int val) ...@@ -190,12 +184,48 @@ putDebugChar(int val)
} }
#endif /* CONFIG_ETRAX_KGDB */ #endif /* CONFIG_ETRAX_KGDB */
static void __init early_putch(int c)
{
reg_ser_r_stat_din stat;
/* Wait until transmitter is ready and send. */
do
stat = REG_RD(ser, port->instance, r_stat_din);
while (!stat.tr_rdy);
REG_WR_INT(ser, port->instance, rw_dout, c);
}
static void __init
early_console_write(struct console *con, const char *s, unsigned n)
{
extern void reset_watchdog(void);
int i;
/* Send data. */
for (i = 0; i < n; i++) {
/* TODO: the '\n' -> '\n\r' translation should be done at the
receiver. Remove it when the serial driver removes it. */
if (s[i] == '\n')
early_putch('\r');
early_putch(s[i]);
reset_watchdog();
}
}
static struct console early_console_dev __initdata = {
.name = "early",
.write = early_console_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1
};
/* Register console for printk's, etc. */ /* Register console for printk's, etc. */
int __init int __init init_etrax_debug(void)
init_etrax_debug(void)
{ {
start_port(port); start_port(port);
/* Register an early console if a debug port was chosen. */
register_console(&early_console_dev);
#ifdef CONFIG_ETRAX_KGDB #ifdef CONFIG_ETRAX_KGDB
start_port(kgdb_port); start_port(kgdb_port);
#endif /* CONFIG_ETRAX_KGDB */ #endif /* CONFIG_ETRAX_KGDB */
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/mm.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/signal.h> #include <asm/signal.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -56,7 +57,6 @@ static int __init etrax_init_cont_rotime(void) ...@@ -56,7 +57,6 @@ static int __init etrax_init_cont_rotime(void)
} }
arch_initcall(etrax_init_cont_rotime); arch_initcall(etrax_init_cont_rotime);
unsigned long timer_regs[NR_CPUS] = unsigned long timer_regs[NR_CPUS] =
{ {
regi_timer0, regi_timer0,
...@@ -68,9 +68,8 @@ unsigned long timer_regs[NR_CPUS] = ...@@ -68,9 +68,8 @@ unsigned long timer_regs[NR_CPUS] =
extern int set_rtc_mmss(unsigned long nowtime); extern int set_rtc_mmss(unsigned long nowtime);
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
static int static int cris_time_freq_notifier(struct notifier_block *nb,
cris_time_freq_notifier(struct notifier_block *nb, unsigned long val, unsigned long val, void *data);
void *data);
static struct notifier_block cris_time_freq_notifier_block = { static struct notifier_block cris_time_freq_notifier_block = {
.notifier_call = cris_time_freq_notifier, .notifier_call = cris_time_freq_notifier,
...@@ -87,7 +86,6 @@ unsigned long get_ns_in_jiffie(void) ...@@ -87,7 +86,6 @@ unsigned long get_ns_in_jiffie(void)
return ns; return ns;
} }
/* From timer MDS describing the hardware watchdog: /* From timer MDS describing the hardware watchdog:
* 4.3.1 Watchdog Operation * 4.3.1 Watchdog Operation
* The watchdog timer is an 8-bit timer with a configurable start value. * The watchdog timer is an 8-bit timer with a configurable start value.
...@@ -109,11 +107,18 @@ static short int watchdog_key = 42; /* arbitrary 7 bit number */ ...@@ -109,11 +107,18 @@ static short int watchdog_key = 42; /* arbitrary 7 bit number */
* is used though, so set this really low. */ * is used though, so set this really low. */
#define WATCHDOG_MIN_FREE_PAGES 8 #define WATCHDOG_MIN_FREE_PAGES 8
/* for reliable NICE_DOGGY behaviour */
static int bite_in_progress;
void reset_watchdog(void) void reset_watchdog(void)
{ {
#if defined(CONFIG_ETRAX_WATCHDOG) #if defined(CONFIG_ETRAX_WATCHDOG)
reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; reg_timer_rw_wd_ctrl wd_ctrl = { 0 };
#if defined(CONFIG_ETRAX_WATCHDOG_NICE_DOGGY)
if (unlikely(bite_in_progress))
return;
#endif
/* Only keep watchdog happy as long as we have memory left! */ /* Only keep watchdog happy as long as we have memory left! */
if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
/* Reset the watchdog with the inverse of the old key */ /* Reset the watchdog with the inverse of the old key */
...@@ -148,7 +153,9 @@ void handle_watchdog_bite(struct pt_regs *regs) ...@@ -148,7 +153,9 @@ void handle_watchdog_bite(struct pt_regs *regs)
#if defined(CONFIG_ETRAX_WATCHDOG) #if defined(CONFIG_ETRAX_WATCHDOG)
extern int cause_of_death; extern int cause_of_death;
nmi_enter();
oops_in_progress = 1; oops_in_progress = 1;
bite_in_progress = 1;
printk(KERN_WARNING "Watchdog bite\n"); printk(KERN_WARNING "Watchdog bite\n");
/* Check if forced restart or unexpected watchdog */ /* Check if forced restart or unexpected watchdog */
...@@ -170,6 +177,7 @@ void handle_watchdog_bite(struct pt_regs *regs) ...@@ -170,6 +177,7 @@ void handle_watchdog_bite(struct pt_regs *regs)
printk(KERN_WARNING "Oops: bitten by watchdog\n"); printk(KERN_WARNING "Oops: bitten by watchdog\n");
show_registers(regs); show_registers(regs);
oops_in_progress = 0; oops_in_progress = 0;
printk("\n"); /* Flush mtdoops. */
#ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY #ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
reset_watchdog(); reset_watchdog();
#endif #endif
...@@ -202,7 +210,7 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id) ...@@ -202,7 +210,7 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id)
/* Reset watchdog otherwise it resets us! */ /* Reset watchdog otherwise it resets us! */
reset_watchdog(); reset_watchdog();
/* Update statistics. */ /* Update statistics. */
update_process_times(user_mode(regs)); update_process_times(user_mode(regs));
cris_do_profile(regs); /* Save profiling information */ cris_do_profile(regs); /* Save profiling information */
...@@ -213,7 +221,7 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id) ...@@ -213,7 +221,7 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id)
/* Call the real timer interrupt handler */ /* Call the real timer interrupt handler */
xtime_update(1); xtime_update(1);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */ /* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */
...@@ -293,14 +301,13 @@ void __init time_init(void) ...@@ -293,14 +301,13 @@ void __init time_init(void)
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&cris_time_freq_notifier_block, cpufreq_register_notifier(&cris_time_freq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER); CPUFREQ_TRANSITION_NOTIFIER);
#endif #endif
} }
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
static int static int cris_time_freq_notifier(struct notifier_block *nb,
cris_time_freq_notifier(struct notifier_block *nb, unsigned long val, unsigned long val, void *data)
void *data)
{ {
struct cpufreq_freqs *freqs = data; struct cpufreq_freqs *freqs = data;
if (val == CPUFREQ_POSTCHANGE) { if (val == CPUFREQ_POSTCHANGE) {
......
...@@ -26,8 +26,7 @@ ...@@ -26,8 +26,7 @@
/* Copy to userspace. This is based on the memcpy used for /* Copy to userspace. This is based on the memcpy used for
kernel-to-kernel copying; see "string.c". */ kernel-to-kernel copying; see "string.c". */
unsigned long unsigned long __copy_user(void __user *pdst, const void *psrc, unsigned long pn)
__copy_user (void __user *pdst, const void *psrc, unsigned long pn)
{ {
/* We want the parameters put in special registers. /* We want the parameters put in special registers.
Make sure the compiler is able to make something useful of this. Make sure the compiler is able to make something useful of this.
...@@ -155,13 +154,13 @@ __copy_user (void __user *pdst, const void *psrc, unsigned long pn) ...@@ -155,13 +154,13 @@ __copy_user (void __user *pdst, const void *psrc, unsigned long pn)
return retn; return retn;
} }
EXPORT_SYMBOL(__copy_user);
/* Copy from user to kernel, zeroing the bytes that were inaccessible in /* Copy from user to kernel, zeroing the bytes that were inaccessible in
userland. The return-value is the number of bytes that were userland. The return-value is the number of bytes that were
inaccessible. */ inaccessible. */
unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
unsigned long unsigned long pn)
__copy_user_zeroing(void *pdst, const void __user *psrc, unsigned long pn)
{ {
/* We want the parameters put in special registers. /* We want the parameters put in special registers.
Make sure the compiler is able to make something useful of this. Make sure the compiler is able to make something useful of this.
...@@ -321,11 +320,10 @@ __copy_user_zeroing(void *pdst, const void __user *psrc, unsigned long pn) ...@@ -321,11 +320,10 @@ __copy_user_zeroing(void *pdst, const void __user *psrc, unsigned long pn)
return retn + n; return retn + n;
} }
EXPORT_SYMBOL(__copy_user_zeroing);
/* Zero userspace. */ /* Zero userspace. */
unsigned long __do_clear_user(void __user *pto, unsigned long pn)
unsigned long
__do_clear_user (void __user *pto, unsigned long pn)
{ {
/* We want the parameters put in special registers. /* We want the parameters put in special registers.
Make sure the compiler is able to make something useful of this. Make sure the compiler is able to make something useful of this.
...@@ -468,3 +466,4 @@ __do_clear_user (void __user *pto, unsigned long pn) ...@@ -468,3 +466,4 @@ __do_clear_user (void __user *pto, unsigned long pn)
return retn; return retn;
} }
EXPORT_SYMBOL(__do_clear_user);
...@@ -26,7 +26,29 @@ static DEFINE_SPINLOCK(pinmux_lock); ...@@ -26,7 +26,29 @@ static DEFINE_SPINLOCK(pinmux_lock);
static void crisv32_pinmux_set(int port); static void crisv32_pinmux_set(int port);
int crisv32_pinmux_init(void) static int __crisv32_pinmux_alloc(int port, int first_pin, int last_pin,
enum pin_mode mode)
{
int i;
for (i = first_pin; i <= last_pin; i++) {
if ((pins[port][i] != pinmux_none)
&& (pins[port][i] != pinmux_gpio)
&& (pins[port][i] != mode)) {
#ifdef DEBUG
panic("Pinmux alloc failed!\n");
#endif
return -EPERM;
}
}
for (i = first_pin; i <= last_pin; i++)
pins[port][i] = mode;
crisv32_pinmux_set(port);
}
static int crisv32_pinmux_init(void)
{ {
static int initialized; static int initialized;
...@@ -37,20 +59,20 @@ int crisv32_pinmux_init(void) ...@@ -37,20 +59,20 @@ int crisv32_pinmux_init(void)
pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 = pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 =
pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes; pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes;
REG_WR(pinmux, regi_pinmux, rw_pa, pa); REG_WR(pinmux, regi_pinmux, rw_pa, pa);
crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio); __crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio);
crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio); __crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio);
crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio); __crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio);
crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio); __crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio);
} }
return 0; return 0;
} }
int int crisv32_pinmux_alloc(int port, int first_pin, int last_pin,
crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) enum pin_mode mode)
{ {
int i;
unsigned long flags; unsigned long flags;
int ret;
crisv32_pinmux_init(); crisv32_pinmux_init();
...@@ -59,26 +81,11 @@ crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) ...@@ -59,26 +81,11 @@ crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
spin_lock_irqsave(&pinmux_lock, flags); spin_lock_irqsave(&pinmux_lock, flags);
for (i = first_pin; i <= last_pin; i++) { ret = __crisv32_pinmux_alloc(port, first_pin, last_pin, mode);
if ((pins[port][i] != pinmux_none)
&& (pins[port][i] != pinmux_gpio)
&& (pins[port][i] != mode)) {
spin_unlock_irqrestore(&pinmux_lock, flags);
#ifdef DEBUG
panic("Pinmux alloc failed!\n");
#endif
return -EPERM;
}
}
for (i = first_pin; i <= last_pin; i++)
pins[port][i] = mode;
crisv32_pinmux_set(port);
spin_unlock_irqrestore(&pinmux_lock, flags); spin_unlock_irqrestore(&pinmux_lock, flags);
return 0; return ret;
} }
int crisv32_pinmux_alloc_fixed(enum fixed_function function) int crisv32_pinmux_alloc_fixed(enum fixed_function function)
...@@ -98,58 +105,58 @@ int crisv32_pinmux_alloc_fixed(enum fixed_function function) ...@@ -98,58 +105,58 @@ int crisv32_pinmux_alloc_fixed(enum fixed_function function)
switch (function) { switch (function) {
case pinmux_ser1: case pinmux_ser1:
ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed);
hwprot.ser1 = regk_pinmux_yes; hwprot.ser1 = regk_pinmux_yes;
break; break;
case pinmux_ser2: case pinmux_ser2:
ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed);
hwprot.ser2 = regk_pinmux_yes; hwprot.ser2 = regk_pinmux_yes;
break; break;
case pinmux_ser3: case pinmux_ser3:
ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed);
hwprot.ser3 = regk_pinmux_yes; hwprot.ser3 = regk_pinmux_yes;
break; break;
case pinmux_sser0: case pinmux_sser0:
ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed);
ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); ret |= __crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
hwprot.sser0 = regk_pinmux_yes; hwprot.sser0 = regk_pinmux_yes;
break; break;
case pinmux_sser1: case pinmux_sser1:
ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
hwprot.sser1 = regk_pinmux_yes; hwprot.sser1 = regk_pinmux_yes;
break; break;
case pinmux_ata0: case pinmux_ata0:
ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed);
ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed); ret |= __crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed);
hwprot.ata0 = regk_pinmux_yes; hwprot.ata0 = regk_pinmux_yes;
break; break;
case pinmux_ata1: case pinmux_ata1:
ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed); ret |= __crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed);
hwprot.ata1 = regk_pinmux_yes; hwprot.ata1 = regk_pinmux_yes;
break; break;
case pinmux_ata2: case pinmux_ata2:
ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed);
ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed); ret |= __crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed);
hwprot.ata2 = regk_pinmux_yes; hwprot.ata2 = regk_pinmux_yes;
break; break;
case pinmux_ata3: case pinmux_ata3:
ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed);
ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed); ret |= __crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed);
hwprot.ata2 = regk_pinmux_yes; hwprot.ata2 = regk_pinmux_yes;
break; break;
case pinmux_ata: case pinmux_ata:
ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed);
ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed); ret |= __crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed);
hwprot.ata = regk_pinmux_yes; hwprot.ata = regk_pinmux_yes;
break; break;
case pinmux_eth1: case pinmux_eth1:
ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed);
hwprot.eth1 = regk_pinmux_yes; hwprot.eth1 = regk_pinmux_yes;
hwprot.eth1_mgm = regk_pinmux_yes; hwprot.eth1_mgm = regk_pinmux_yes;
break; break;
case pinmux_timer: case pinmux_timer:
ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); ret = __crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
hwprot.timer = regk_pinmux_yes; hwprot.timer = regk_pinmux_yes;
spin_unlock_irqrestore(&pinmux_lock, flags); spin_unlock_irqrestore(&pinmux_lock, flags);
return ret; return ret;
...@@ -188,9 +195,19 @@ void crisv32_pinmux_set(int port) ...@@ -188,9 +195,19 @@ void crisv32_pinmux_set(int port)
#endif #endif
} }
int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) static int __crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
{ {
int i; int i;
for (i = first_pin; i <= last_pin; i++)
pins[port][i] = pinmux_none;
crisv32_pinmux_set(port);
return 0;
}
int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
{
unsigned long flags; unsigned long flags;
crisv32_pinmux_init(); crisv32_pinmux_init();
...@@ -199,11 +216,7 @@ int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) ...@@ -199,11 +216,7 @@ int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&pinmux_lock, flags); spin_lock_irqsave(&pinmux_lock, flags);
__crisv32_pinmux_dealloc(port, first_pin, last_pin);
for (i = first_pin; i <= last_pin; i++)
pins[port][i] = pinmux_none;
crisv32_pinmux_set(port);
spin_unlock_irqrestore(&pinmux_lock, flags); spin_unlock_irqrestore(&pinmux_lock, flags);
return 0; return 0;
...@@ -226,58 +239,58 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function) ...@@ -226,58 +239,58 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function)
switch (function) { switch (function) {
case pinmux_ser1: case pinmux_ser1:
ret = crisv32_pinmux_dealloc(PORT_C, 4, 7); ret = __crisv32_pinmux_dealloc(PORT_C, 4, 7);
hwprot.ser1 = regk_pinmux_no; hwprot.ser1 = regk_pinmux_no;
break; break;
case pinmux_ser2: case pinmux_ser2:
ret = crisv32_pinmux_dealloc(PORT_C, 8, 11); ret = __crisv32_pinmux_dealloc(PORT_C, 8, 11);
hwprot.ser2 = regk_pinmux_no; hwprot.ser2 = regk_pinmux_no;
break; break;
case pinmux_ser3: case pinmux_ser3:
ret = crisv32_pinmux_dealloc(PORT_C, 12, 15); ret = __crisv32_pinmux_dealloc(PORT_C, 12, 15);
hwprot.ser3 = regk_pinmux_no; hwprot.ser3 = regk_pinmux_no;
break; break;
case pinmux_sser0: case pinmux_sser0:
ret = crisv32_pinmux_dealloc(PORT_C, 0, 3); ret = __crisv32_pinmux_dealloc(PORT_C, 0, 3);
ret |= crisv32_pinmux_dealloc(PORT_C, 16, 16); ret |= __crisv32_pinmux_dealloc(PORT_C, 16, 16);
hwprot.sser0 = regk_pinmux_no; hwprot.sser0 = regk_pinmux_no;
break; break;
case pinmux_sser1: case pinmux_sser1:
ret = crisv32_pinmux_dealloc(PORT_D, 0, 4); ret = __crisv32_pinmux_dealloc(PORT_D, 0, 4);
hwprot.sser1 = regk_pinmux_no; hwprot.sser1 = regk_pinmux_no;
break; break;
case pinmux_ata0: case pinmux_ata0:
ret = crisv32_pinmux_dealloc(PORT_D, 5, 7); ret = __crisv32_pinmux_dealloc(PORT_D, 5, 7);
ret |= crisv32_pinmux_dealloc(PORT_D, 15, 17); ret |= __crisv32_pinmux_dealloc(PORT_D, 15, 17);
hwprot.ata0 = regk_pinmux_no; hwprot.ata0 = regk_pinmux_no;
break; break;
case pinmux_ata1: case pinmux_ata1:
ret = crisv32_pinmux_dealloc(PORT_D, 0, 4); ret = __crisv32_pinmux_dealloc(PORT_D, 0, 4);
ret |= crisv32_pinmux_dealloc(PORT_E, 17, 17); ret |= __crisv32_pinmux_dealloc(PORT_E, 17, 17);
hwprot.ata1 = regk_pinmux_no; hwprot.ata1 = regk_pinmux_no;
break; break;
case pinmux_ata2: case pinmux_ata2:
ret = crisv32_pinmux_dealloc(PORT_C, 11, 15); ret = __crisv32_pinmux_dealloc(PORT_C, 11, 15);
ret |= crisv32_pinmux_dealloc(PORT_E, 3, 3); ret |= __crisv32_pinmux_dealloc(PORT_E, 3, 3);
hwprot.ata2 = regk_pinmux_no; hwprot.ata2 = regk_pinmux_no;
break; break;
case pinmux_ata3: case pinmux_ata3:
ret = crisv32_pinmux_dealloc(PORT_C, 8, 10); ret = __crisv32_pinmux_dealloc(PORT_C, 8, 10);
ret |= crisv32_pinmux_dealloc(PORT_C, 0, 2); ret |= __crisv32_pinmux_dealloc(PORT_C, 0, 2);
hwprot.ata2 = regk_pinmux_no; hwprot.ata2 = regk_pinmux_no;
break; break;
case pinmux_ata: case pinmux_ata:
ret = crisv32_pinmux_dealloc(PORT_B, 0, 15); ret = __crisv32_pinmux_dealloc(PORT_B, 0, 15);
ret |= crisv32_pinmux_dealloc(PORT_D, 8, 15); ret |= __crisv32_pinmux_dealloc(PORT_D, 8, 15);
hwprot.ata = regk_pinmux_no; hwprot.ata = regk_pinmux_no;
break; break;
case pinmux_eth1: case pinmux_eth1:
ret = crisv32_pinmux_dealloc(PORT_E, 0, 17); ret = __crisv32_pinmux_dealloc(PORT_E, 0, 17);
hwprot.eth1 = regk_pinmux_no; hwprot.eth1 = regk_pinmux_no;
hwprot.eth1_mgm = regk_pinmux_no; hwprot.eth1_mgm = regk_pinmux_no;
break; break;
case pinmux_timer: case pinmux_timer:
ret = crisv32_pinmux_dealloc(PORT_C, 16, 16); ret = __crisv32_pinmux_dealloc(PORT_C, 16, 16);
hwprot.timer = regk_pinmux_no; hwprot.timer = regk_pinmux_no;
spin_unlock_irqrestore(&pinmux_lock, flags); spin_unlock_irqrestore(&pinmux_lock, flags);
return ret; return ret;
...@@ -293,7 +306,8 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function) ...@@ -293,7 +306,8 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function)
return ret; return ret;
} }
void crisv32_pinmux_dump(void) #ifdef DEBUG
static void crisv32_pinmux_dump(void)
{ {
int i, j; int i, j;
...@@ -305,5 +319,5 @@ void crisv32_pinmux_dump(void) ...@@ -305,5 +319,5 @@ void crisv32_pinmux_dump(void)
printk(KERN_DEBUG " Pin %d = %d\n", j, pins[i][j]); printk(KERN_DEBUG " Pin %d = %d\n", j, pins[i][j]);
} }
} }
#endif
__initcall(crisv32_pinmux_init); __initcall(crisv32_pinmux_init);
...@@ -28,11 +28,9 @@ enum fixed_function { ...@@ -28,11 +28,9 @@ enum fixed_function {
pinmux_timer pinmux_timer
}; };
int crisv32_pinmux_init(void);
int crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode); int crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode);
int crisv32_pinmux_alloc_fixed(enum fixed_function function); int crisv32_pinmux_alloc_fixed(enum fixed_function function);
int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin); int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin);
int crisv32_pinmux_dealloc_fixed(enum fixed_function function); int crisv32_pinmux_dealloc_fixed(enum fixed_function function);
void crisv32_pinmux_dump(void);
#endif #endif
header-y += arch-v10/
header-y += arch-v32/
generic-y += barrier.h generic-y += barrier.h
generic-y += clkdev.h generic-y += clkdev.h
generic-y += cputime.h generic-y += cputime.h
......
# UAPI Header export list # UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm include include/uapi/asm-generic/Kbuild.asm
header-y += arch-v10/ header-y += ../arch-v10/arch/
header-y += arch-v32/ header-y += ../arch-v32/arch/
header-y += auxvec.h header-y += auxvec.h
header-y += bitsperlong.h header-y += bitsperlong.h
header-y += byteorder.h header-y += byteorder.h
......
...@@ -47,16 +47,16 @@ EXPORT_SYMBOL(__negdi2); ...@@ -47,16 +47,16 @@ EXPORT_SYMBOL(__negdi2);
EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(iounmap);
/* Userspace access functions */
EXPORT_SYMBOL(__copy_user_zeroing);
EXPORT_SYMBOL(__copy_user);
#undef memcpy #undef memcpy
#undef memset #undef memset
extern void * memset(void *, int, __kernel_size_t); extern void * memset(void *, int, __kernel_size_t);
extern void * memcpy(void *, const void *, __kernel_size_t); extern void * memcpy(void *, const void *, __kernel_size_t);
EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memset);
#ifdef CONFIG_ETRAX_ARCH_V32
#undef strcmp
EXPORT_SYMBOL(strcmp);
#endif
#ifdef CONFIG_ETRAX_FAST_TIMER #ifdef CONFIG_ETRAX_FAST_TIMER
/* Fast timer functions */ /* Fast timer functions */
...@@ -66,3 +66,4 @@ EXPORT_SYMBOL(del_fast_timer); ...@@ -66,3 +66,4 @@ EXPORT_SYMBOL(del_fast_timer);
EXPORT_SYMBOL(schedule_usleep); EXPORT_SYMBOL(schedule_usleep);
#endif #endif
EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_from_user);
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/utsname.h>
#ifdef CONFIG_KALLSYMS
#include <linux/kallsyms.h>
#endif
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -34,25 +38,24 @@ static int kstack_depth_to_print = 24; ...@@ -34,25 +38,24 @@ static int kstack_depth_to_print = 24;
void (*nmi_handler)(struct pt_regs *); void (*nmi_handler)(struct pt_regs *);
void void show_trace(unsigned long *stack)
show_trace(unsigned long *stack)
{ {
unsigned long addr, module_start, module_end; unsigned long addr, module_start, module_end;
extern char _stext, _etext; extern char _stext, _etext;
int i; int i;
printk("\nCall Trace: "); pr_err("\nCall Trace: ");
i = 1; i = 1;
module_start = VMALLOC_START; module_start = VMALLOC_START;
module_end = VMALLOC_END; module_end = VMALLOC_END;
while (((long)stack & (THREAD_SIZE-1)) != 0) { while (((long)stack & (THREAD_SIZE - 1)) != 0) {
if (__get_user(addr, stack)) { if (__get_user(addr, stack)) {
/* This message matches "failing address" marked /* This message matches "failing address" marked
s390 in ksymoops, so lines containing it will s390 in ksymoops, so lines containing it will
not be filtered out by ksymoops. */ not be filtered out by ksymoops. */
printk("Failing address 0x%lx\n", (unsigned long)stack); pr_err("Failing address 0x%lx\n", (unsigned long)stack);
break; break;
} }
stack++; stack++;
...@@ -68,10 +71,14 @@ show_trace(unsigned long *stack) ...@@ -68,10 +71,14 @@ show_trace(unsigned long *stack)
if (((addr >= (unsigned long)&_stext) && if (((addr >= (unsigned long)&_stext) &&
(addr <= (unsigned long)&_etext)) || (addr <= (unsigned long)&_etext)) ||
((addr >= module_start) && (addr <= module_end))) { ((addr >= module_start) && (addr <= module_end))) {
#ifdef CONFIG_KALLSYMS
print_ip_sym(addr);
#else
if (i && ((i % 8) == 0)) if (i && ((i % 8) == 0))
printk("\n "); pr_err("\n ");
printk("[<%08lx>] ", addr); pr_err("[<%08lx>] ", addr);
i++; i++;
#endif
} }
} }
} }
...@@ -111,21 +118,21 @@ show_stack(struct task_struct *task, unsigned long *sp) ...@@ -111,21 +118,21 @@ show_stack(struct task_struct *task, unsigned long *sp)
stack = sp; stack = sp;
printk("\nStack from %08lx:\n ", (unsigned long)stack); pr_err("\nStack from %08lx:\n ", (unsigned long)stack);
for (i = 0; i < kstack_depth_to_print; i++) { for (i = 0; i < kstack_depth_to_print; i++) {
if (((long)stack & (THREAD_SIZE-1)) == 0) if (((long)stack & (THREAD_SIZE-1)) == 0)
break; break;
if (i && ((i % 8) == 0)) if (i && ((i % 8) == 0))
printk("\n "); pr_err("\n ");
if (__get_user(addr, stack)) { if (__get_user(addr, stack)) {
/* This message matches "failing address" marked /* This message matches "failing address" marked
s390 in ksymoops, so lines containing it will s390 in ksymoops, so lines containing it will
not be filtered out by ksymoops. */ not be filtered out by ksymoops. */
printk("Failing address 0x%lx\n", (unsigned long)stack); pr_err("Failing address 0x%lx\n", (unsigned long)stack);
break; break;
} }
stack++; stack++;
printk("%08lx ", addr); pr_err("%08lx ", addr);
} }
show_trace(sp); show_trace(sp);
} }
...@@ -139,33 +146,32 @@ show_stack(void) ...@@ -139,33 +146,32 @@ show_stack(void)
unsigned long *sp = (unsigned long *)rdusp(); unsigned long *sp = (unsigned long *)rdusp();
int i; int i;
printk("Stack dump [0x%08lx]:\n", (unsigned long)sp); pr_err("Stack dump [0x%08lx]:\n", (unsigned long)sp);
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
printk("sp + %d: 0x%08lx\n", i*4, sp[i]); pr_err("sp + %d: 0x%08lx\n", i*4, sp[i]);
return 0; return 0;
} }
#endif #endif
void void set_nmi_handler(void (*handler)(struct pt_regs *))
set_nmi_handler(void (*handler)(struct pt_regs *))
{ {
nmi_handler = handler; nmi_handler = handler;
arch_enable_nmi(); arch_enable_nmi();
} }
#ifdef CONFIG_DEBUG_NMI_OOPS #ifdef CONFIG_DEBUG_NMI_OOPS
void void oops_nmi_handler(struct pt_regs *regs)
oops_nmi_handler(struct pt_regs *regs)
{ {
stop_watchdog(); stop_watchdog();
oops_in_progress = 1; oops_in_progress = 1;
printk("NMI!\n"); pr_err("NMI!\n");
show_registers(regs); show_registers(regs);
oops_in_progress = 0; oops_in_progress = 0;
oops_exit();
pr_err("\n"); /* Flush mtdoops. */
} }
static int __init static int __init oops_nmi_register(void)
oops_nmi_register(void)
{ {
set_nmi_handler(oops_nmi_handler); set_nmi_handler(oops_nmi_handler);
return 0; return 0;
...@@ -180,8 +186,7 @@ __initcall(oops_nmi_register); ...@@ -180,8 +186,7 @@ __initcall(oops_nmi_register);
* similar to an Oops dump, and if the kernel is configured to be a nice * similar to an Oops dump, and if the kernel is configured to be a nice
* doggy, then halt instead of reboot. * doggy, then halt instead of reboot.
*/ */
void void watchdog_bite_hook(struct pt_regs *regs)
watchdog_bite_hook(struct pt_regs *regs)
{ {
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
local_irq_disable(); local_irq_disable();
...@@ -196,8 +201,7 @@ watchdog_bite_hook(struct pt_regs *regs) ...@@ -196,8 +201,7 @@ watchdog_bite_hook(struct pt_regs *regs)
} }
/* This is normally the Oops function. */ /* This is normally the Oops function. */
void void die_if_kernel(const char *str, struct pt_regs *regs, long err)
die_if_kernel(const char *str, struct pt_regs *regs, long err)
{ {
if (user_mode(regs)) if (user_mode(regs))
return; return;
...@@ -211,13 +215,17 @@ die_if_kernel(const char *str, struct pt_regs *regs, long err) ...@@ -211,13 +215,17 @@ die_if_kernel(const char *str, struct pt_regs *regs, long err)
stop_watchdog(); stop_watchdog();
#endif #endif
oops_enter();
handle_BUG(regs); handle_BUG(regs);
printk("%s: %04lx\n", str, err & 0xffff); pr_err("Linux %s %s\n", utsname()->release, utsname()->version);
pr_err("%s: %04lx\n", str, err & 0xffff);
show_registers(regs); show_registers(regs);
oops_exit();
oops_in_progress = 0; oops_in_progress = 0;
pr_err("\n"); /* Flush mtdoops. */
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
reset_watchdog(); reset_watchdog();
...@@ -225,8 +233,7 @@ die_if_kernel(const char *str, struct pt_regs *regs, long err) ...@@ -225,8 +233,7 @@ die_if_kernel(const char *str, struct pt_regs *regs, long err)
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
void __init void __init trap_init(void)
trap_init(void)
{ {
/* Nothing needs to be done */ /* Nothing needs to be done */
} }
...@@ -11,13 +11,15 @@ ...@@ -11,13 +11,15 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/proc_fs.h>
#include <linux/kcore.h>
#include <asm/tlb.h> #include <asm/tlb.h>
#include <asm/sections.h> #include <asm/sections.h>
unsigned long empty_zero_page; unsigned long empty_zero_page;
EXPORT_SYMBOL(empty_zero_page);
void __init void __init mem_init(void)
mem_init(void)
{ {
BUG_ON(!mem_map); BUG_ON(!mem_map);
...@@ -31,10 +33,36 @@ mem_init(void) ...@@ -31,10 +33,36 @@ mem_init(void)
mem_init_print_info(NULL); mem_init_print_info(NULL);
} }
/* free the pages occupied by initialization code */ /* Free a range of init pages. Virtual addresses. */
void void free_init_pages(const char *what, unsigned long begin, unsigned long end)
free_initmem(void) {
unsigned long addr;
for (addr = begin; addr < end; addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
init_page_count(virt_to_page(addr));
free_page(addr);
totalram_pages++;
}
printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
}
/* Free the pages occupied by initialization code. */
void free_initmem(void)
{ {
free_initmem_default(-1); free_initmem_default(-1);
} }
/* Free the pages occupied by initrd code. */
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
free_init_pages("initrd memory",
start,
end);
}
#endif
...@@ -76,10 +76,11 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l ...@@ -76,10 +76,11 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
* Must be freed with iounmap. * Must be freed with iounmap.
*/ */
void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) void __iomem *ioremap_nocache(unsigned long phys_addr, unsigned long size)
{ {
return __ioremap(phys_addr | MEM_NON_CACHEABLE, size, 0); return __ioremap(phys_addr | MEM_NON_CACHEABLE, size, 0);
} }
EXPORT_SYMBOL(ioremap_nocache);
void iounmap(volatile void __iomem *addr) void iounmap(volatile void __iomem *addr)
{ {
......
...@@ -19,8 +19,6 @@ for arch in ${archs}; do ...@@ -19,8 +19,6 @@ for arch in ${archs}; do
case ${arch} in case ${arch} in
um) # no userspace export um) # no userspace export
;; ;;
cris) # headers export are known broken
;;
*) *)
if [ -d ${srctree}/arch/${arch} ]; then if [ -d ${srctree}/arch/${arch} ]; then
do_command $1 ${arch} do_command $1 ${arch}
......
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