Commit 63245d2c authored by Mikael Starvik's avatar Mikael Starvik Committed by Linus Torvalds

[PATCH] CRIS update: I/O and DMA allocator

Added I/O and DMA allocators to be used by drivers.
Signed-off-by: default avatarMikael Starvik <starvik@axis.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7e920426
/* Wrapper for DMA channel allocator that updates DMA client muxing.
* Copyright 2004, Axis Communications AB
* $Id: dma.c,v 1.1 2004/12/13 12:21:51 starvik Exp $
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <asm/dma.h>
#include <asm/arch/svinto.h>
/* Macro to access ETRAX 100 registers */
#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \
IO_STATE_(reg##_, field##_, _##val)
static char used_dma_channels[MAX_DMA_CHANNELS];
static const char * used_dma_channels_users[MAX_DMA_CHANNELS];
int cris_request_dma(unsigned int dmanr, const char * device_id,
unsigned options, enum dma_owner owner)
{
unsigned long flags;
unsigned long int gens;
int fail = -EINVAL;
if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) {
printk(KERN_CRIT "cris_request_dma: invalid DMA channel %u\n", dmanr);
return -EINVAL;
}
local_irq_save(flags);
if (used_dma_channels[dmanr]) {
local_irq_restore(flags);
if (options & DMA_VERBOSE_ON_ERROR) {
printk(KERN_CRIT "Failed to request DMA %i for %s, already allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]);
}
if (options & DMA_PANIC_ON_ERROR) {
panic("request_dma error!");
}
return -EBUSY;
}
gens = genconfig_shadow;
switch(owner)
{
case dma_eth:
if ((dmanr != NETWORK_TX_DMA_NBR) &&
(dmanr != NETWORK_RX_DMA_NBR)) {
printk(KERN_CRIT "Invalid DMA channel for eth\n");
goto bail;
}
break;
case dma_ser0:
if (dmanr == SER0_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma6, serial0);
} else if (dmanr == SER0_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma7, serial0);
} else {
printk(KERN_CRIT "Invalid DMA channel for ser0\n");
goto bail;
}
break;
case dma_ser1:
if (dmanr == SER1_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma8, serial1);
} else if (dmanr == SER1_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma9, serial1);
} else {
printk(KERN_CRIT "Invalid DMA channel for ser1\n");
goto bail;
}
break;
case dma_ser2:
if (dmanr == SER2_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma2, serial2);
} else if (dmanr == SER2_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma3, serial2);
} else {
printk(KERN_CRIT "Invalid DMA channel for ser2\n");
goto bail;
}
break;
case dma_ser3:
if (dmanr == SER3_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma4, serial3);
} else if (dmanr == SER3_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma5, serial3);
} else {
printk(KERN_CRIT "Invalid DMA channel for ser3\n");
goto bail;
}
break;
case dma_ata:
if (dmanr == ATA_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma2, ata);
} else if (dmanr == ATA_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma3, ata);
} else {
printk(KERN_CRIT "Invalid DMA channel for ata\n");
goto bail;
}
break;
case dma_ext0:
if (dmanr == EXTDMA0_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma4, extdma0);
} else if (dmanr == EXTDMA0_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma5, extdma0);
} else {
printk(KERN_CRIT "Invalid DMA channel for ext0\n");
goto bail;
}
break;
case dma_ext1:
if (dmanr == EXTDMA1_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma6, extdma1);
} else if (dmanr == EXTDMA1_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma7, extdma1);
} else {
printk(KERN_CRIT "Invalid DMA channel for ext1\n");
goto bail;
}
break;
case dma_int6:
if (dmanr == MEM2MEM_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma7, intdma6);
} else {
printk(KERN_CRIT "Invalid DMA channel for int6\n");
goto bail;
}
break;
case dma_int7:
if (dmanr == MEM2MEM_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma6, intdma7);
} else {
printk(KERN_CRIT "Invalid DMA channel for int7\n");
goto bail;
}
break;
case dma_usb:
if (dmanr == USB_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma8, usb);
} else if (dmanr == USB_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma9, usb);
} else {
printk(KERN_CRIT "Invalid DMA channel for usb\n");
goto bail;
}
break;
case dma_scsi0:
if (dmanr == SCSI0_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma2, scsi0);
} else if (dmanr == SCSI0_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma3, scsi0);
} else {
printk(KERN_CRIT "Invalid DMA channel for scsi0\n");
goto bail;
}
break;
case dma_scsi1:
if (dmanr == SCSI1_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma4, scsi1);
} else if (dmanr == SCSI1_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma5, scsi1);
} else {
printk(KERN_CRIT "Invalid DMA channel for scsi1\n");
goto bail;
}
break;
case dma_par0:
if (dmanr == PAR0_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma2, par0);
} else if (dmanr == PAR0_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma3, par0);
} else {
printk(KERN_CRIT "Invalid DMA channel for par0\n");
goto bail;
}
break;
case dma_par1:
if (dmanr == PAR1_TX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma4, par1);
} else if (dmanr == PAR1_RX_DMA_NBR) {
SETS(gens, R_GEN_CONFIG, dma5, par1);
} else {
printk(KERN_CRIT "Invalid DMA channel for par1\n");
goto bail;
}
break;
default:
printk(KERN_CRIT "Invalid DMA owner.\n");
goto bail;
}
used_dma_channels[dmanr] = 1;
used_dma_channels_users[dmanr] = device_id;
{
volatile int i;
genconfig_shadow = gens;
*R_GEN_CONFIG = genconfig_shadow;
/* Wait 12 cycles before doing any DMA command */
for(i = 6; i > 0; i--)
nop();
}
fail = 0;
bail:
local_irq_restore(flags);
return fail;
}
void cris_free_dma(unsigned int dmanr, const char * device_id)
{
unsigned long flags;
if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) {
printk(KERN_CRIT "cris_free_dma: invalid DMA channel %u\n", dmanr);
return;
}
local_irq_save(flags);
if (!used_dma_channels[dmanr]) {
printk(KERN_CRIT "cris_free_dma: DMA channel %u not allocated\n", dmanr);
} else if (device_id != used_dma_channels_users[dmanr]) {
printk(KERN_CRIT "cris_free_dma: DMA channel %u not allocated by device\n", dmanr);
} else {
switch(dmanr)
{
case 0:
*R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH0_CMD, cmd, *R_DMA_CH0_CMD) ==
IO_STATE_VALUE(R_DMA_CH0_CMD, cmd, reset));
break;
case 1:
*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH1_CMD, cmd, *R_DMA_CH1_CMD) ==
IO_STATE_VALUE(R_DMA_CH1_CMD, cmd, reset));
break;
case 2:
*R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH2_CMD, cmd, *R_DMA_CH2_CMD) ==
IO_STATE_VALUE(R_DMA_CH2_CMD, cmd, reset));
break;
case 3:
*R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH3_CMD, cmd, *R_DMA_CH3_CMD) ==
IO_STATE_VALUE(R_DMA_CH3_CMD, cmd, reset));
break;
case 4:
*R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH4_CMD, cmd, *R_DMA_CH4_CMD) ==
IO_STATE_VALUE(R_DMA_CH4_CMD, cmd, reset));
break;
case 5:
*R_DMA_CH5_CMD = IO_STATE(R_DMA_CH5_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH5_CMD, cmd, *R_DMA_CH5_CMD) ==
IO_STATE_VALUE(R_DMA_CH5_CMD, cmd, reset));
break;
case 6:
*R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *R_DMA_CH6_CMD) ==
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
break;
case 7:
*R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH7_CMD, cmd, *R_DMA_CH7_CMD) ==
IO_STATE_VALUE(R_DMA_CH7_CMD, cmd, reset));
break;
case 8:
*R_DMA_CH8_CMD = IO_STATE(R_DMA_CH8_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH8_CMD, cmd, *R_DMA_CH8_CMD) ==
IO_STATE_VALUE(R_DMA_CH8_CMD, cmd, reset));
break;
case 9:
*R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH9_CMD, cmd, *R_DMA_CH9_CMD) ==
IO_STATE_VALUE(R_DMA_CH9_CMD, cmd, reset));
break;
}
used_dma_channels[dmanr] = 0;
}
local_irq_restore(flags);
}
EXPORT_SYMBOL(cris_request_dma);
EXPORT_SYMBOL(cris_free_dma);
/* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik Exp $
/* $Id: head.S,v 1.10 2005/06/20 05:12:54 starvik Exp $
*
* Head of the kernel - alter with care
*
......@@ -7,6 +7,16 @@
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: head.S,v $
* Revision 1.10 2005/06/20 05:12:54 starvik
* Remove unnecessary diff to kernel.org tree
*
* Revision 1.9 2004/12/13 12:21:51 starvik
* Added I/O and DMA allocators from Linux 2.4
*
* Revision 1.8 2004/11/22 11:41:14 starvik
* Kernel command line may be supplied to kernel. Not used by Axis but may
* be used by customers.
*
* Revision 1.7 2004/05/14 07:58:01 starvik
* Merge of changes from 2.4
*
......@@ -181,6 +191,7 @@
#define CRAMFS_MAGIC 0x28cd3d45
#define RAM_INIT_MAGIC 0x56902387
#define COMMAND_LINE_MAGIC 0x87109563
#define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\
IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk)
......@@ -490,6 +501,23 @@ _no_romfs_in_flash:
_start_it:
;; Check if kernel command line is supplied
cmp.d COMMAND_LINE_MAGIC, $r10
bne no_command_line
nop
move.d 256, $r13
move.d cris_command_line, $r10
or.d 0x80000000, $r11 ; Make it virtual
1:
move.b [$r11+], $r12
move.b $r12, [$r10+]
subq 1, $r13
bne 1b
nop
no_command_line:
;; the kernel stack is overlayed with the task structure for each
;; task. thus the initial kernel stack is in the same page as the
;; init_task (but starts in the top of the page, size 8192)
......@@ -567,76 +595,32 @@ _start_it:
;; Etrax product HW genconfig setup
moveq 0,$r0
#if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \
&& !defined(CONFIG_DMA_MEMCPY)
; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \
| IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0
#endif
#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1)
; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
or.d IO_STATE (R_GEN_CONFIG, dma9, serial1) \
| IO_STATE (R_GEN_CONFIG, dma8, serial1),$r0
#endif
#ifdef CONFIG_DMA_MEMCPY
; 6/7 memory-memory DMA
or.d IO_STATE (R_GEN_CONFIG, dma7, intdma6) \
| IO_STATE (R_GEN_CONFIG, dma6, intdma7),$r0
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT2
; Enable serial port 2
or.w IO_STATE (R_GEN_CONFIG, ser2, select),$r0
#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT2)
; DMA channels 2 and 3 to ser2, kgdb doesnt want DMA
or.d IO_STATE (R_GEN_CONFIG, dma3, serial2) \
| IO_STATE (R_GEN_CONFIG, dma2, serial2),$r0
#endif
#endif
#if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
; Enable serial port 3
or.w IO_STATE (R_GEN_CONFIG, ser3, select),$r0
#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT3)
; DMA channels 4 and 5 to ser3, kgdb doesnt want DMA
or.d IO_STATE (R_GEN_CONFIG, dma5, serial3) \
| IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0
#endif
#endif
#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
; parport 0 enabled using DMA 2/3
or.w IO_STATE (R_GEN_CONFIG, par0, select),$r0
#endif
#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
; parport 1 enabled using DMA 4/5
or.w IO_STATE (R_GEN_CONFIG, par1, select),$r0
#endif
#ifdef CONFIG_ETRAX_IDE
; DMA channels 2 and 3 to ATA, ATA enabled
or.d IO_STATE (R_GEN_CONFIG, dma3, ata) \
| IO_STATE (R_GEN_CONFIG, dma2, ata) \
| IO_STATE (R_GEN_CONFIG, ata, select),$r0
#endif
#ifdef CONFIG_ETRAX_USB_HOST_PORT1
; Set the USB port 1 enable bit
or.d IO_STATE (R_GEN_CONFIG, usb1, select),$r0
#endif
#ifdef CONFIG_ETRAX_USB_HOST_PORT2
; Set the USB port 2 enable bit
or.d IO_STATE (R_GEN_CONFIG, usb2, select),$r0
#endif
#ifdef CONFIG_ETRAX_USB_HOST
; Connect DMA channels 8 and 9 to USB
and.d (~(IO_MASK (R_GEN_CONFIG, dma9) \
| IO_MASK (R_GEN_CONFIG, dma8))) \
| IO_STATE (R_GEN_CONFIG, dma9, usb) \
| IO_STATE (R_GEN_CONFIG, dma8, usb),$r0
#endif
#ifdef CONFIG_JULIETTE
; DMA channels 4 and 5 to EXTDMA0, for Juliette
or.d IO_STATE (R_GEN_CONFIG, dma5, extdma0) \
| IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0
#endif
;; Init interfaces (disable them).
or.d IO_STATE (R_GEN_CONFIG, scsi0, disable) \
| IO_STATE (R_GEN_CONFIG, ata, disable) \
| IO_STATE (R_GEN_CONFIG, par0, disable) \
| IO_STATE (R_GEN_CONFIG, ser2, disable) \
| IO_STATE (R_GEN_CONFIG, mio, disable) \
| IO_STATE (R_GEN_CONFIG, scsi1, disable) \
| IO_STATE (R_GEN_CONFIG, scsi0w, disable) \
| IO_STATE (R_GEN_CONFIG, par1, disable) \
| IO_STATE (R_GEN_CONFIG, ser3, disable) \
| IO_STATE (R_GEN_CONFIG, mio_w, disable) \
| IO_STATE (R_GEN_CONFIG, usb1, disable) \
| IO_STATE (R_GEN_CONFIG, usb2, disable) \
| IO_STATE (R_GEN_CONFIG, par_w, disable),$r0
;; Init DMA channel muxing (set to unused clients).
or.d IO_STATE (R_GEN_CONFIG, dma2, ata) \
| IO_STATE (R_GEN_CONFIG, dma3, ata) \
| IO_STATE (R_GEN_CONFIG, dma4, scsi1) \
| IO_STATE (R_GEN_CONFIG, dma5, scsi1) \
| IO_STATE (R_GEN_CONFIG, dma6, unused) \
| IO_STATE (R_GEN_CONFIG, dma7, unused) \
| IO_STATE (R_GEN_CONFIG, dma8, usb) \
| IO_STATE (R_GEN_CONFIG, dma9, usb),$r0
#if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT)
or.d IO_STATE (R_GEN_CONFIG, g0dir, out),$r0
......
This diff is collapsed.
/* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $
/* $Id: shadows.c,v 1.2 2004/12/13 12:21:51 starvik Exp $
*
* Various shadow registers. Defines for these are in include/asm-etrax100/io.h
*/
......@@ -6,6 +6,7 @@
/* Shadows for internal Etrax-registers */
unsigned long genconfig_shadow;
unsigned long gen_config_ii_shadow;
unsigned long port_g_data_shadow;
unsigned char port_pa_dir_shadow;
unsigned char port_pa_data_shadow;
......
......@@ -44,3 +44,31 @@
#define USB_RX_DMA_NBR 9
#endif
enum dma_owner
{
dma_eth,
dma_ser0,
dma_ser1, /* Async and sync */
dma_ser2,
dma_ser3, /* Async and sync */
dma_ata,
dma_par0,
dma_par1,
dma_ext0,
dma_ext1,
dma_int6,
dma_int7,
dma_usb,
dma_scsi0,
dma_scsi1
};
/* Masks used by cris_request_dma options: */
#define DMA_VERBOSE_ON_ERROR (1<<0)
#define DMA_PANIC_ON_ERROR ((1<<1)|DMA_VERBOSE_ON_ERROR)
int cris_request_dma(unsigned int dmanr, const char * device_id,
unsigned options, enum dma_owner owner);
void cris_free_dma(unsigned int dmanr, const char * device_id);
......@@ -6,6 +6,7 @@
/* Etrax shadow registers - which live in arch/cris/kernel/shadows.c */
extern unsigned long gen_config_ii_shadow;
extern unsigned long port_g_data_shadow;
extern unsigned char port_pa_dir_shadow;
extern unsigned char port_pa_data_shadow;
......
/* IO interface mux allocator for ETRAX100LX.
* Copyright 2004, Axis Communications AB
* $Id: io_interface_mux.h,v 1.1 2004/12/13 12:21:53 starvik Exp $
*/
#ifndef _IO_INTERFACE_MUX_H
#define _IO_INTERFACE_MUX_H
/* C.f. ETRAX100LX Designer's Reference 20.9 */
/* The order in enum must match the order of interfaces[] in
* io_interface_mux.c */
enum cris_io_interface {
/* Begin Non-multiplexed interfaces */
if_eth = 0,
if_serial_0,
/* End Non-multiplexed interfaces */
if_serial_1,
if_serial_2,
if_serial_3,
if_sync_serial_1,
if_sync_serial_3,
if_shared_ram,
if_shared_ram_w,
if_par_0,
if_par_1,
if_par_w,
if_scsi8_0,
if_scsi8_1,
if_scsi_w,
if_ata,
if_csp,
if_i2c,
if_usb_1,
if_usb_2,
/* GPIO pins */
if_gpio_grp_a,
if_gpio_grp_b,
if_gpio_grp_c,
if_gpio_grp_d,
if_gpio_grp_e,
if_gpio_grp_f,
if_max_interfaces,
if_unclaimed
};
int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id);
void cris_free_io_interface(enum cris_io_interface ioif);
/* port can be 'a', 'b' or 'g' */
int cris_io_interface_allocate_pins(const enum cris_io_interface ioif,
const char port,
const unsigned start_bit,
const unsigned stop_bit);
/* port can be 'a', 'b' or 'g' */
int cris_io_interface_free_pins(const enum cris_io_interface ioif,
const char port,
const unsigned start_bit,
const unsigned stop_bit);
int cris_io_interface_register_watcher(void (*notify)(const unsigned int gpio_in_available,
const unsigned int gpio_out_available,
const unsigned char pa_available,
const unsigned char pb_available));
void cris_io_interface_delete_watcher(void (*notify)(const unsigned int gpio_in_available,
const unsigned int gpio_out_available,
const unsigned char pa_available,
const unsigned char pb_available));
#endif /* _IO_INTERFACE_MUX_H */
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