diff options
Diffstat (limited to 'arch/xtensa/platforms')
| -rw-r--r-- | arch/xtensa/platforms/iss/Makefile | 6 | ||||
| -rw-r--r-- | arch/xtensa/platforms/iss/console.c | 48 | ||||
| -rw-r--r-- | arch/xtensa/platforms/iss/include/platform/serial.h | 15 | ||||
| -rw-r--r-- | arch/xtensa/platforms/iss/include/platform/simcall.h | 55 | ||||
| -rw-r--r-- | arch/xtensa/platforms/iss/io.c | 32 | ||||
| -rw-r--r-- | arch/xtensa/platforms/iss/network.c | 353 | ||||
| -rw-r--r-- | arch/xtensa/platforms/iss/setup.c | 20 | ||||
| -rw-r--r-- | arch/xtensa/platforms/iss/simdisk.c | 384 | ||||
| -rw-r--r-- | arch/xtensa/platforms/xt2000/setup.c | 24 | ||||
| -rw-r--r-- | arch/xtensa/platforms/xtfpga/Makefile | 9 | ||||
| -rw-r--r-- | arch/xtensa/platforms/xtfpga/include/platform/hardware.h | 65 | ||||
| -rw-r--r-- | arch/xtensa/platforms/xtfpga/include/platform/lcd.h | 20 | ||||
| -rw-r--r-- | arch/xtensa/platforms/xtfpga/include/platform/serial.h | 18 | ||||
| -rw-r--r-- | arch/xtensa/platforms/xtfpga/lcd.c | 76 | ||||
| -rw-r--r-- | arch/xtensa/platforms/xtfpga/setup.c | 303 |
15 files changed, 1089 insertions, 339 deletions
diff --git a/arch/xtensa/platforms/iss/Makefile b/arch/xtensa/platforms/iss/Makefile index af96e314d71..b3e89291cfb 100644 --- a/arch/xtensa/platforms/iss/Makefile +++ b/arch/xtensa/platforms/iss/Makefile @@ -4,5 +4,7 @@ # "prom monitor" library routines under Linux. # -obj-y = io.o console.o setup.o network.o - +obj-y = setup.o +obj-$(CONFIG_TTY) += console.o +obj-$(CONFIG_NET) += network.o +obj-$(CONFIG_BLK_DEV_SIMDISK) += simdisk.o diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index f9726f6afdf..70cb408bc20 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -33,7 +33,7 @@ #endif #define SERIAL_MAX_NUM_LINES 1 -#define SERIAL_TIMER_VALUE (20 * HZ) +#define SERIAL_TIMER_VALUE (HZ / 10) static struct tty_driver *serial_driver; static struct tty_port serial_port; @@ -41,19 +41,6 @@ static struct timer_list serial_timer; static DEFINE_SPINLOCK(timer_lock); -int errno; - -static int __simc (int a, int b, int c, int d, int e, int f) __attribute__((__noinline__)); -static int __simc (int a, int b, int c, int d, int e, int f) -{ - int ret; - __asm__ __volatile__ ("simcall\n" - "mov %0, a2\n" - "mov %1, a3\n" : "=a" (ret), "=a" (errno) - : : "a2", "a3"); - return ret; -} - static char *serial_version = "0.1"; static char *serial_name = "ISS serial driver"; @@ -69,12 +56,13 @@ static void rs_poll(unsigned long); static int rs_open(struct tty_struct *tty, struct file * filp) { tty->port = &serial_port; - spin_lock(&timer_lock); + spin_lock_bh(&timer_lock); if (tty->count == 1) { - setup_timer(&serial_timer, rs_poll, (unsigned long)tty); + setup_timer(&serial_timer, rs_poll, + (unsigned long)&serial_port); mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); } - spin_unlock(&timer_lock); + spin_unlock_bh(&timer_lock); return 0; } @@ -104,28 +92,26 @@ static int rs_write(struct tty_struct * tty, { /* see drivers/char/serialX.c to reference original version */ - __simc (SYS_write, 1, (unsigned long)buf, count, 0, 0); + simc_write(1, buf, count); return count; } static void rs_poll(unsigned long priv) { - struct tty_struct* tty = (struct tty_struct*) priv; - - struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; + struct tty_port *port = (struct tty_port *)priv; int i = 0; unsigned char c; spin_lock(&timer_lock); - while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){ - __simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0); - tty_insert_flip_char(tty, c, TTY_NORMAL); + while (simc_poll(0)) { + simc_read(0, &c, 1); + tty_insert_flip_char(port, c, TTY_NORMAL); i++; } if (i) - tty_flip_buffer_push(tty); + tty_flip_buffer_push(port); mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE); @@ -135,12 +121,7 @@ static void rs_poll(unsigned long priv) static int rs_put_char(struct tty_struct *tty, unsigned char ch) { - char buf[2]; - - buf[0] = ch; - buf[1] = '\0'; /* Is this NULL necessary? */ - __simc (SYS_write, 1, (unsigned long) buf, 1, 0, 0); - return 1; + return rs_write(tty, &ch, 1); } static void rs_flush_chars(struct tty_struct *tty) @@ -223,6 +204,7 @@ int __init rs_init(void) serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &serial_ops); + tty_port_link_device(&serial_port, serial_driver, 0); if (tty_register_driver(serial_driver)) panic("Couldn't register serial driver\n"); @@ -238,6 +220,7 @@ static __exit void rs_exit(void) printk("ISS_SERIAL: failed to unregister serial driver (%d)\n", error); put_tty_driver(serial_driver); + tty_port_destroy(&serial_port); } @@ -260,8 +243,7 @@ static void iss_console_write(struct console *co, const char *s, unsigned count) int len = strlen(s); if (s != 0 && *s != 0) - __simc (SYS_write, 1, (unsigned long)s, - count < len ? count : len,0,0); + simc_write(1, s, count < len ? count : len); } static struct tty_driver* iss_console_device(struct console *c, int *index) diff --git a/arch/xtensa/platforms/iss/include/platform/serial.h b/arch/xtensa/platforms/iss/include/platform/serial.h new file mode 100644 index 00000000000..16aec542d43 --- /dev/null +++ b/arch/xtensa/platforms/iss/include/platform/serial.h @@ -0,0 +1,15 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 Tensilica Inc. + */ + +#ifndef __ASM_XTENSA_ISS_SERIAL_H +#define __ASM_XTENSA_ISS_SERIAL_H + +/* Have no meaning on ISS, but needed for 8250_early.c */ +#define BASE_BAUD 0 + +#endif /* __ASM_XTENSA_ISS_SERIAL_H */ diff --git a/arch/xtensa/platforms/iss/include/platform/simcall.h b/arch/xtensa/platforms/iss/include/platform/simcall.h index b7952c06a2b..12b15ad1e58 100644 --- a/arch/xtensa/platforms/iss/include/platform/simcall.h +++ b/arch/xtensa/platforms/iss/include/platform/simcall.h @@ -57,6 +57,61 @@ #define XTISS_SELECT_ONE_WRITE 2 #define XTISS_SELECT_ONE_EXCEPT 3 +static int errno; + +static inline int __simc(int a, int b, int c, int d) +{ + int ret; + register int a1 asm("a2") = a; + register int b1 asm("a3") = b; + register int c1 asm("a4") = c; + register int d1 asm("a5") = d; + __asm__ __volatile__ ( + "simcall\n" + "mov %0, a2\n" + "mov %1, a3\n" + : "=a" (ret), "=a" (errno), "+r"(a1), "+r"(b1) + : "r"(c1), "r"(d1) + : "memory"); + return ret; +} + +static inline int simc_open(const char *file, int flags, int mode) +{ + return __simc(SYS_open, (int) file, flags, mode); +} + +static inline int simc_close(int fd) +{ + return __simc(SYS_close, fd, 0, 0); +} + +static inline int simc_ioctl(int fd, int request, void *arg) +{ + return __simc(SYS_ioctl, fd, request, (int) arg); +} + +static inline int simc_read(int fd, void *buf, size_t count) +{ + return __simc(SYS_read, fd, (int) buf, count); +} + +static inline int simc_write(int fd, const void *buf, size_t count) +{ + return __simc(SYS_write, fd, (int) buf, count); +} + +static inline int simc_poll(int fd) +{ + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; + + return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv); +} + +static inline int simc_lseek(int fd, uint32_t off, int whence) +{ + return __simc(SYS_lseek, fd, off, whence); +} #endif /* _XTENSA_PLATFORM_ISS_SIMCALL_H */ diff --git a/arch/xtensa/platforms/iss/io.c b/arch/xtensa/platforms/iss/io.c deleted file mode 100644 index 571d0b24f89..00000000000 --- a/arch/xtensa/platforms/iss/io.c +++ /dev/null @@ -1,32 +0,0 @@ -/* This file isn't really needed right now. */ - -#if 0 - -#include <asm/io.h> -#include <platform/platform-iss/simcall.h> - -extern int __simc (); - - -char iss_serial_getc() -{ - char c; - __simc( SYS_read, 0, &c, 1 ); - return c; -} - -void iss_serial_putc( char c ) -{ - __simc( SYS_write, 1, &c, 1 ); -} - -void iss_serial_puts( char *s ) -{ - if( s != 0 && *s != 0 ) - __simc( SYS_write, 1, s, strlen(s) ); -} - -/*#error Need I/O ports to specific hardware!*/ - -#endif - diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index 7dde2445642..d05f8feeb8d 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -38,7 +38,7 @@ #define DRIVER_NAME "iss-netdev" #define ETH_MAX_PACKET 1500 #define ETH_HEADER_OTHER 14 -#define ISS_NET_TIMER_VALUE (2 * HZ) +#define ISS_NET_TIMER_VALUE (HZ / 10) static DEFINE_SPINLOCK(opened_lock); @@ -56,8 +56,6 @@ static LIST_HEAD(devices); struct tuntap_info { char dev_name[IFNAMSIZ]; - int fixed_config; - unsigned char gw[ETH_ALEN]; int fd; }; @@ -67,7 +65,6 @@ struct tuntap_info { /* This structure contains out private information for the driver. */ struct iss_net_private { - struct list_head device_list; struct list_head opened_list; @@ -83,9 +80,6 @@ struct iss_net_private { int index; int mtu; - unsigned char mac[ETH_ALEN]; - int have_mac; - struct { union { struct tuntap_info tuntap; @@ -101,55 +95,6 @@ struct iss_net_private { }; -/* ======================= ISS SIMCALL INTERFACE =========================== */ - -/* Note: __simc must _not_ be declared inline! */ - -static int errno; - -static int __simc (int a, int b, int c, int d, int e, int f) __attribute__((__noinline__)); -static int __simc (int a, int b, int c, int d, int e, int f) -{ - int ret; - __asm__ __volatile__ ("simcall\n" - "mov %0, a2\n" - "mov %1, a3\n" : "=a" (ret), "=a" (errno) - : : "a2", "a3"); - return ret; -} - -static int inline simc_open(char *file, int flags, int mode) -{ - return __simc(SYS_open, (int) file, flags, mode, 0, 0); -} - -static int inline simc_close(int fd) -{ - return __simc(SYS_close, fd, 0, 0, 0, 0); -} - -static int inline simc_ioctl(int fd, int request, void *arg) -{ - return __simc(SYS_ioctl, fd, request, (int) arg, 0, 0); -} - -static int inline simc_read(int fd, void *buf, size_t count) -{ - return __simc(SYS_read, fd, (int) buf, count, 0, 0); -} - -static int inline simc_write(int fd, void *buf, size_t count) -{ - return __simc(SYS_write, fd, (int) buf, count, 0, 0); -} - -static int inline simc_poll(int fd) -{ - struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; - - return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv,0,0); -} - /* ================================ HELPERS ================================ */ @@ -167,68 +112,48 @@ static char *split_if_spec(char *str, ...) *arg = str; if (end == NULL) return NULL; - *end ++ = '\0'; + *end++ = '\0'; str = end; } va_end(ap); return str; } +/* Set Ethernet address of the specified device. */ -#if 0 -/* Adjust SKB. */ - -struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) +static void setup_etheraddr(struct net_device *dev, char *str) { - if ((skb != NULL) && (skb_tailroom(skb) < extra)) { - struct sk_buff *skb2; + unsigned char *addr = dev->dev_addr; - skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC); - dev_kfree_skb(skb); - skb = skb2; - } - if (skb != NULL) - skb_put(skb, extra); + if (str == NULL) + goto random; - return skb; -} -#endif - -/* Return the IP address as a string for a given device. */ - -static void dev_ip_addr(void *d, char *buf, char *bin_buf) -{ - struct net_device *dev = d; - struct in_device *ip = dev->ip_ptr; - struct in_ifaddr *in; - __be32 addr; - - if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) { - printk(KERN_WARNING "Device not assigned an IP address!\n"); - return; + if (!mac_pton(str, addr)) { + pr_err("%s: failed to parse '%s' as an ethernet address\n", + dev->name, str); + goto random; } - - addr = in->ifa_address; - sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, - (addr >> 16) & 0xff, addr >> 24); - - if (bin_buf) { - bin_buf[0] = addr & 0xff; - bin_buf[1] = (addr >> 8) & 0xff; - bin_buf[2] = (addr >> 16) & 0xff; - bin_buf[3] = addr >> 24; + if (is_multicast_ether_addr(addr)) { + pr_err("%s: attempt to assign a multicast ethernet address\n", + dev->name); + goto random; } -} - -/* Set Ethernet address of the specified device. */ + if (!is_valid_ether_addr(addr)) { + pr_err("%s: attempt to assign an invalid ethernet address\n", + dev->name); + goto random; + } + if (!is_local_ether_addr(addr)) + pr_warn("%s: assigning a globally valid ethernet address\n", + dev->name); + return; -static void inline set_ether_mac(void *d, unsigned char *addr) -{ - struct net_device *dev = d; - memcpy(dev->dev_addr, addr, ETH_ALEN); +random: + pr_info("%s: choosing a random ethernet address\n", + dev->name); + eth_hw_addr_random(dev); } - /* ======================= TUNTAP TRANSPORT INTERFACE ====================== */ static int tuntap_open(struct iss_net_private *lp) @@ -238,24 +163,21 @@ static int tuntap_open(struct iss_net_private *lp) int err = -EINVAL; int fd; - /* We currently only support a fixed configuration. */ - - if (!lp->tp.info.tuntap.fixed_config) - return -EINVAL; - - if ((fd = simc_open("/dev/net/tun", 02, 0)) < 0) { /* O_RDWR */ - printk("Failed to open /dev/net/tun, returned %d " - "(errno = %d)\n", fd, errno); + fd = simc_open("/dev/net/tun", 02, 0); /* O_RDWR */ + if (fd < 0) { + pr_err("%s: failed to open /dev/net/tun, returned %d (errno = %d)\n", + lp->dev->name, fd, errno); return fd; } - memset(&ifr, 0, sizeof ifr); + memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name); + strlcpy(ifr.ifr_name, dev_name, sizeof(ifr.ifr_name)); - if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) { - printk("Failed to set interface, returned %d " - "(errno = %d)\n", err, errno); + err = simc_ioctl(fd, TUNSETIFF, &ifr); + if (err < 0) { + pr_err("%s: failed to set interface %s, returned %d (errno = %d)\n", + lp->dev->name, dev_name, err, errno); simc_close(fd); return err; } @@ -266,27 +188,17 @@ static int tuntap_open(struct iss_net_private *lp) static void tuntap_close(struct iss_net_private *lp) { -#if 0 - if (lp->tp.info.tuntap.fixed_config) - iter_addresses(lp->tp.info.tuntap.dev, close_addr, lp->host.dev_name); -#endif simc_close(lp->tp.info.tuntap.fd); lp->tp.info.tuntap.fd = -1; } -static int tuntap_read (struct iss_net_private *lp, struct sk_buff **skb) +static int tuntap_read(struct iss_net_private *lp, struct sk_buff **skb) { -#if 0 - *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); - if (*skb == NULL) - return -ENOMEM; -#endif - return simc_read(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER); } -static int tuntap_write (struct iss_net_private *lp, struct sk_buff **skb) +static int tuntap_write(struct iss_net_private *lp, struct sk_buff **skb) { return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len); } @@ -302,45 +214,45 @@ static int tuntap_poll(struct iss_net_private *lp) } /* - * Currently only a device name is supported. - * ethX=tuntap[,[mac address][,[device name]]] + * ethX=tuntap,[mac address],device name */ static int tuntap_probe(struct iss_net_private *lp, int index, char *init) { - const int len = strlen(TRANSPORT_TUNTAP_NAME); + struct net_device *dev = lp->dev; char *dev_name = NULL, *mac_str = NULL, *rem = NULL; /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */ - if (strncmp(init, TRANSPORT_TUNTAP_NAME, len)) + if (strncmp(init, TRANSPORT_TUNTAP_NAME, + sizeof(TRANSPORT_TUNTAP_NAME) - 1)) return 0; - if (*(init += strlen(TRANSPORT_TUNTAP_NAME)) == ',') { - if ((rem=split_if_spec(init+1, &mac_str, &dev_name)) != NULL) { - printk("Extra garbage on specification : '%s'\n", rem); + init += sizeof(TRANSPORT_TUNTAP_NAME) - 1; + if (*init == ',') { + rem = split_if_spec(init + 1, &mac_str, &dev_name); + if (rem != NULL) { + pr_err("%s: extra garbage on specification : '%s'\n", + dev->name, rem); return 0; } } else if (*init != '\0') { - printk("Invalid argument: %s. Skipping device!\n", init); + pr_err("%s: invalid argument: %s. Skipping device!\n", + dev->name, init); return 0; } - if (dev_name) { - strncpy(lp->tp.info.tuntap.dev_name, dev_name, - sizeof lp->tp.info.tuntap.dev_name); - lp->tp.info.tuntap.fixed_config = 1; - } else - strcpy(lp->tp.info.tuntap.dev_name, TRANSPORT_TUNTAP_NAME); + if (!dev_name) { + pr_err("%s: missing tuntap device name\n", dev->name); + return 0; + } + strlcpy(lp->tp.info.tuntap.dev_name, dev_name, + sizeof(lp->tp.info.tuntap.dev_name)); -#if 0 - if (setup_etheraddr(mac_str, lp->mac)) - lp->have_mac = 1; -#endif - lp->mtu = TRANSPORT_TUNTAP_MTU; + setup_etheraddr(dev, mac_str); - //lp->info.tuntap.gate_addr = gate_addr; + lp->mtu = TRANSPORT_TUNTAP_MTU; lp->tp.info.tuntap.fd = -1; @@ -351,13 +263,6 @@ static int tuntap_probe(struct iss_net_private *lp, int index, char *init) lp->tp.protocol = tuntap_protocol; lp->tp.poll = tuntap_poll; - printk("TUN/TAP backend - "); -#if 0 - if (lp->host.gate_addr != NULL) - printk("IP = %s", lp->host.gate_addr); -#endif - printk("\n"); - return 1; } @@ -376,7 +281,8 @@ static int iss_net_rx(struct net_device *dev) /* Try to allocate memory, if it fails, try again next round. */ - if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) { + skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER); + if (skb == NULL) { lp->stats.rx_dropped++; return 0; } @@ -396,7 +302,6 @@ static int iss_net_rx(struct net_device *dev) lp->stats.rx_bytes += skb->len; lp->stats.rx_packets++; - // netif_rx(skb); netif_rx_ni(skb); return pkt_len; } @@ -427,11 +332,11 @@ static int iss_net_poll(void) spin_unlock(&lp->lock); if (err < 0) { - printk(KERN_ERR "Device '%s' read returned %d, " - "shutting it down\n", lp->dev->name, err); + pr_err("Device '%s' read returned %d, shutting it down\n", + lp->dev->name, err); dev_close(lp->dev); } else { - // FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ); + /* FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ); */ } } @@ -442,14 +347,11 @@ static int iss_net_poll(void) static void iss_net_timer(unsigned long priv) { - struct iss_net_private* lp = (struct iss_net_private*) priv; + struct iss_net_private *lp = (struct iss_net_private *)priv; spin_lock(&lp->lock); - iss_net_poll(); - mod_timer(&lp->timer, jiffies + lp->timer_val); - spin_unlock(&lp->lock); } @@ -457,19 +359,14 @@ static void iss_net_timer(unsigned long priv) static int iss_net_open(struct net_device *dev) { struct iss_net_private *lp = netdev_priv(dev); - char addr[sizeof "255.255.255.255\0"]; int err; spin_lock(&lp->lock); - if ((err = lp->tp.open(lp)) < 0) + err = lp->tp.open(lp); + if (err < 0) goto out; - if (!lp->have_mac) { - dev_ip_addr(dev, addr, &lp->mac[2]); - set_ether_mac(dev, lp->mac); - } - netif_start_queue(dev); /* clear buffer - it can happen that the host side of the interface @@ -497,7 +394,6 @@ out: static int iss_net_close(struct net_device *dev) { struct iss_net_private *lp = netdev_priv(dev); -printk("iss_net_close!\n"); netif_stop_queue(dev); spin_lock(&lp->lock); @@ -539,7 +435,7 @@ static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) } else { netif_start_queue(dev); - printk(KERN_ERR "iss_net_start_xmit: failed(%d)\n", len); + pr_err("%s: %s failed(%d)\n", dev->name, __func__, len); } spin_unlock_irqrestore(&lp->lock, flags); @@ -557,56 +453,27 @@ static struct net_device_stats *iss_net_get_stats(struct net_device *dev) static void iss_net_set_multicast_list(struct net_device *dev) { -#if 0 - if (dev->flags & IFF_PROMISC) - return; - else if (!netdev_mc_empty(dev)) - dev->flags |= IFF_ALLMULTI; - else - dev->flags &= ~IFF_ALLMULTI; -#endif } static void iss_net_tx_timeout(struct net_device *dev) { -#if 0 - dev->trans_start = jiffies; - netif_wake_queue(dev); -#endif } static int iss_net_set_mac(struct net_device *dev, void *addr) { -#if 0 struct iss_net_private *lp = netdev_priv(dev); struct sockaddr *hwaddr = addr; + if (!is_valid_ether_addr(hwaddr->sa_data)) + return -EADDRNOTAVAIL; spin_lock(&lp->lock); memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); spin_unlock(&lp->lock); -#endif - return 0; } static int iss_net_change_mtu(struct net_device *dev, int new_mtu) { -#if 0 - struct iss_net_private *lp = netdev_priv(dev); - int err = 0; - - spin_lock(&lp->lock); - - // FIXME not needed new_mtu = transport_set_mtu(new_mtu, &lp->user); - - if (new_mtu < 0) - err = new_mtu; - else - dev->mtu = new_mtu; - - spin_unlock(&lp->lock); - return err; -#endif return -EINVAL; } @@ -631,7 +498,6 @@ static const struct net_device_ops iss_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = iss_net_change_mtu, .ndo_set_mac_address = iss_net_set_mac, - //.ndo_do_ioctl = iss_net_ioctl, .ndo_tx_timeout = iss_net_tx_timeout, .ndo_set_rx_mode = iss_net_set_multicast_list, }; @@ -642,24 +508,29 @@ static int iss_net_configure(int index, char *init) struct iss_net_private *lp; int err; - if ((dev = alloc_etherdev(sizeof *lp)) == NULL) { - printk(KERN_ERR "eth_configure: failed to allocate device\n"); + dev = alloc_etherdev(sizeof(*lp)); + if (dev == NULL) { + pr_err("eth_configure: failed to allocate device\n"); return 1; } /* Initialize private element. */ lp = netdev_priv(dev); - *lp = ((struct iss_net_private) { + *lp = (struct iss_net_private) { .device_list = LIST_HEAD_INIT(lp->device_list), .opened_list = LIST_HEAD_INIT(lp->opened_list), .lock = __SPIN_LOCK_UNLOCKED(lp.lock), .dev = dev, .index = index, - //.fd = -1, - .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }, - .have_mac = 0, - }); + }; + + /* + * If this name ends up conflicting with an existing registered + * netdevice, that is OK, register_netdev{,ice}() will notice this + * and fail. + */ + snprintf(dev->name, sizeof(dev->name), "eth%d", index); /* * Try all transport protocols. @@ -667,14 +538,12 @@ static int iss_net_configure(int index, char *init) */ if (!tuntap_probe(lp, index, init)) { - printk("Invalid arguments. Skipping device!\n"); + pr_err("%s: invalid arguments. Skipping device!\n", + dev->name); goto errout; } - printk(KERN_INFO "Netdevice %d ", index); - if (lp->have_mac) - printk("(%pM) ", lp->mac); - printk(": "); + pr_info("Netdevice %d (%pM)\n", index, dev->dev_addr); /* sysfs register */ @@ -690,14 +559,7 @@ static int iss_net_configure(int index, char *init) lp->pdev.id = index; lp->pdev.name = DRIVER_NAME; platform_device_register(&lp->pdev); - SET_NETDEV_DEV(dev,&lp->pdev.dev); - - /* - * If this name ends up conflicting with an existing registered - * netdevice, that is OK, register_netdev{,ice}() will notice this - * and fail. - */ - snprintf(dev->name, sizeof dev->name, "eth%d", index); + SET_NETDEV_DEV(dev, &lp->pdev.dev); dev->netdev_ops = &iss_netdev_ops; dev->mtu = lp->mtu; @@ -709,7 +571,7 @@ static int iss_net_configure(int index, char *init) rtnl_unlock(); if (err) { - printk("Error registering net device!\n"); + pr_err("%s: error registering net device!\n", dev->name); /* XXX: should we call ->remove() here? */ free_netdev(dev); return 1; @@ -718,16 +580,11 @@ static int iss_net_configure(int index, char *init) init_timer(&lp->tl); lp->tl.function = iss_net_user_timer_expire; -#if 0 - if (lp->have_mac) - set_ether_mac(dev, lp->mac); -#endif return 0; errout: - // FIXME: unregister; free, etc.. + /* FIXME: unregister; free, etc.. */ return -EIO; - } /* ------------------------------------------------------------------------- */ @@ -749,27 +606,28 @@ struct iss_net_init { #define ERR KERN_ERR "iss_net_setup: " -static int iss_net_setup(char *str) +static int __init iss_net_setup(char *str) { struct iss_net_private *device = NULL; struct iss_net_init *new; struct list_head *ele; char *end; - int n; + int rc; + unsigned n; - n = simple_strtoul(str, &end, 0); - if (end == str) { - printk(ERR "Failed to parse '%s'\n", str); - return 1; - } - if (n < 0) { - printk(ERR "Device %d is negative\n", n); + end = strchr(str, '='); + if (!end) { + printk(ERR "Expected '=' after device number\n"); return 1; } - if (*(str = end) != '=') { - printk(ERR "Expected '=' after device number\n"); + *end = 0; + rc = kstrtouint(str, 0, &n); + *end = '='; + if (rc < 0) { + printk(ERR "Failed to parse '%s'\n", str); return 1; } + str = end; spin_lock(&devices_lock); @@ -782,12 +640,13 @@ static int iss_net_setup(char *str) spin_unlock(&devices_lock); if (device && device->index == n) { - printk(ERR "Device %d already configured\n", n); + printk(ERR "Device %u already configured\n", n); return 1; } - if ((new = alloc_bootmem(sizeof new)) == NULL) { - printk("Alloc_bootmem failed\n"); + new = alloc_bootmem(sizeof(*new)); + if (new == NULL) { + printk(ERR "Alloc_bootmem failed\n"); return 1; } @@ -801,7 +660,7 @@ static int iss_net_setup(char *str) #undef ERR -__setup("eth=", iss_net_setup); +__setup("eth", iss_net_setup); /* * Initialize all ISS Ethernet devices previously registered in iss_net_setup. diff --git a/arch/xtensa/platforms/iss/setup.c b/arch/xtensa/platforms/iss/setup.c index f60c8cf6dfb..da7d1824086 100644 --- a/arch/xtensa/platforms/iss/setup.c +++ b/arch/xtensa/platforms/iss/setup.c @@ -40,14 +40,14 @@ void __init platform_init(bp_tag_t* bootparam) void platform_halt(void) { - printk (" ** Called platform_halt(), looping forever! **\n"); - while (1); + pr_info(" ** Called platform_halt() **\n"); + __asm__ __volatile__("movi a2, 1\nsimcall\n"); } void platform_power_off(void) { - printk (" ** Called platform_power_off(), looping forever! **\n"); - while (1); + pr_info(" ** Called platform_power_off() **\n"); + __asm__ __volatile__("movi a2, 1\nsimcall\n"); } void platform_restart(void) { @@ -55,13 +55,15 @@ void platform_restart(void) * jump to the reset vector. */ __asm__ __volatile__("movi a2, 15\n\t" - "wsr a2, " __stringify(ICOUNTLEVEL) "\n\t" + "wsr a2, icountlevel\n\t" "movi a2, 0\n\t" - "wsr a2, " __stringify(ICOUNT) "\n\t" - "wsr a2, " __stringify(IBREAKENABLE) "\n\t" - "wsr a2, " __stringify(LCOUNT) "\n\t" + "wsr a2, icount\n\t" +#if XCHAL_NUM_IBREAK > 0 + "wsr a2, ibreakenable\n\t" +#endif + "wsr a2, lcount\n\t" "movi a2, 0x1f\n\t" - "wsr a2, " __stringify(PS) "\n\t" + "wsr a2, ps\n\t" "isync\n\t" "jx %0\n\t" : diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c new file mode 100644 index 00000000000..48eebacdf5f --- /dev/null +++ b/arch/xtensa/platforms/iss/simdisk.c @@ -0,0 +1,384 @@ +/* + * arch/xtensa/platforms/iss/simdisk.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001-2013 Tensilica Inc. + * Authors Victor Prupis + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/blkdev.h> +#include <linux/bio.h> +#include <linux/proc_fs.h> +#include <asm/uaccess.h> +#include <platform/simcall.h> + +#define SIMDISK_MAJOR 240 +#define SECTOR_SHIFT 9 +#define SIMDISK_MINORS 1 +#define MAX_SIMDISK_COUNT 10 + +struct simdisk { + const char *filename; + spinlock_t lock; + struct request_queue *queue; + struct gendisk *gd; + struct proc_dir_entry *procfile; + int users; + unsigned long size; + int fd; +}; + + +static int simdisk_count = CONFIG_BLK_DEV_SIMDISK_COUNT; +module_param(simdisk_count, int, S_IRUGO); +MODULE_PARM_DESC(simdisk_count, "Number of simdisk units."); + +static int n_files; +static const char *filename[MAX_SIMDISK_COUNT] = { +#ifdef CONFIG_SIMDISK0_FILENAME + CONFIG_SIMDISK0_FILENAME, +#ifdef CONFIG_SIMDISK1_FILENAME + CONFIG_SIMDISK1_FILENAME, +#endif +#endif +}; + +static int simdisk_param_set_filename(const char *val, + const struct kernel_param *kp) +{ + if (n_files < ARRAY_SIZE(filename)) + filename[n_files++] = val; + else + return -EINVAL; + return 0; +} + +static const struct kernel_param_ops simdisk_param_ops_filename = { + .set = simdisk_param_set_filename, +}; +module_param_cb(filename, &simdisk_param_ops_filename, &n_files, 0); +MODULE_PARM_DESC(filename, "Backing storage filename."); + +static int simdisk_major = SIMDISK_MAJOR; + +static void simdisk_transfer(struct simdisk *dev, unsigned long sector, + unsigned long nsect, char *buffer, int write) +{ + unsigned long offset = sector << SECTOR_SHIFT; + unsigned long nbytes = nsect << SECTOR_SHIFT; + + if (offset > dev->size || dev->size - offset < nbytes) { + pr_notice("Beyond-end %s (%ld %ld)\n", + write ? "write" : "read", offset, nbytes); + return; + } + + spin_lock(&dev->lock); + while (nbytes > 0) { + unsigned long io; + + simc_lseek(dev->fd, offset, SEEK_SET); + if (write) + io = simc_write(dev->fd, buffer, nbytes); + else + io = simc_read(dev->fd, buffer, nbytes); + if (io == -1) { + pr_err("SIMDISK: IO error %d\n", errno); + break; + } + buffer += io; + offset += io; + nbytes -= io; + } + spin_unlock(&dev->lock); +} + +static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio) +{ + struct bio_vec bvec; + struct bvec_iter iter; + sector_t sector = bio->bi_iter.bi_sector; + + bio_for_each_segment(bvec, bio, iter) { + char *buffer = __bio_kmap_atomic(bio, iter); + unsigned len = bvec.bv_len >> SECTOR_SHIFT; + + simdisk_transfer(dev, sector, len, buffer, + bio_data_dir(bio) == WRITE); + sector += len; + __bio_kunmap_atomic(buffer); + } + return 0; +} + +static void simdisk_make_request(struct request_queue *q, struct bio *bio) +{ + struct simdisk *dev = q->queuedata; + int status = simdisk_xfer_bio(dev, bio); + bio_endio(bio, status); +} + + +static int simdisk_open(struct block_device *bdev, fmode_t mode) +{ + struct simdisk *dev = bdev->bd_disk->private_data; + + spin_lock(&dev->lock); + if (!dev->users) + check_disk_change(bdev); + ++dev->users; + spin_unlock(&dev->lock); + return 0; +} + +static void simdisk_release(struct gendisk *disk, fmode_t mode) +{ + struct simdisk *dev = disk->private_data; + spin_lock(&dev->lock); + --dev->users; + spin_unlock(&dev->lock); +} + +static const struct block_device_operations simdisk_ops = { + .owner = THIS_MODULE, + .open = simdisk_open, + .release = simdisk_release, +}; + +static struct simdisk *sddev; +static struct proc_dir_entry *simdisk_procdir; + +static int simdisk_attach(struct simdisk *dev, const char *filename) +{ + int err = 0; + + filename = kstrdup(filename, GFP_KERNEL); + if (filename == NULL) + return -ENOMEM; + + spin_lock(&dev->lock); + + if (dev->fd != -1) { + err = -EBUSY; + goto out; + } + dev->fd = simc_open(filename, O_RDWR, 0); + if (dev->fd == -1) { + pr_err("SIMDISK: Can't open %s: %d\n", filename, errno); + err = -ENODEV; + goto out; + } + dev->size = simc_lseek(dev->fd, 0, SEEK_END); + set_capacity(dev->gd, dev->size >> SECTOR_SHIFT); + dev->filename = filename; + pr_info("SIMDISK: %s=%s\n", dev->gd->disk_name, dev->filename); +out: + if (err) + kfree(filename); + spin_unlock(&dev->lock); + + return err; +} + +static int simdisk_detach(struct simdisk *dev) +{ + int err = 0; + + spin_lock(&dev->lock); + + if (dev->users != 0) { + err = -EBUSY; + } else if (dev->fd != -1) { + if (simc_close(dev->fd)) { + pr_err("SIMDISK: error closing %s: %d\n", + dev->filename, errno); + err = -EIO; + } else { + pr_info("SIMDISK: %s detached from %s\n", + dev->gd->disk_name, dev->filename); + dev->fd = -1; + kfree(dev->filename); + dev->filename = NULL; + } + } + spin_unlock(&dev->lock); + return err; +} + +static ssize_t proc_read_simdisk(struct file *file, char __user *buf, + size_t size, loff_t *ppos) +{ + struct simdisk *dev = PDE_DATA(file_inode(file)); + const char *s = dev->filename; + if (s) { + ssize_t n = simple_read_from_buffer(buf, size, ppos, + s, strlen(s)); + if (n < 0) + return n; + buf += n; + size -= n; + } + return simple_read_from_buffer(buf, size, ppos, "\n", 1); +} + +static ssize_t proc_write_simdisk(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char *tmp = kmalloc(count + 1, GFP_KERNEL); + struct simdisk *dev = PDE_DATA(file_inode(file)); + int err; + + if (tmp == NULL) + return -ENOMEM; + if (copy_from_user(tmp, buf, count)) { + err = -EFAULT; + goto out_free; + } + + err = simdisk_detach(dev); + if (err != 0) + goto out_free; + + if (count > 0 && tmp[count - 1] == '\n') + tmp[count - 1] = 0; + else + tmp[count] = 0; + + if (tmp[0]) + err = simdisk_attach(dev, tmp); + + if (err == 0) + err = count; +out_free: + kfree(tmp); + return err; +} + +static const struct file_operations fops = { + .read = proc_read_simdisk, + .write = proc_write_simdisk, + .llseek = default_llseek, +}; + +static int __init simdisk_setup(struct simdisk *dev, int which, + struct proc_dir_entry *procdir) +{ + char tmp[2] = { '0' + which, 0 }; + + dev->fd = -1; + dev->filename = NULL; + spin_lock_init(&dev->lock); + dev->users = 0; + + dev->queue = blk_alloc_queue(GFP_KERNEL); + if (dev->queue == NULL) { + pr_err("blk_alloc_queue failed\n"); + goto out_alloc_queue; + } + + blk_queue_make_request(dev->queue, simdisk_make_request); + dev->queue->queuedata = dev; + + dev->gd = alloc_disk(SIMDISK_MINORS); + if (dev->gd == NULL) { + pr_err("alloc_disk failed\n"); + goto out_alloc_disk; + } + dev->gd->major = simdisk_major; + dev->gd->first_minor = which; + dev->gd->fops = &simdisk_ops; + dev->gd->queue = dev->queue; + dev->gd->private_data = dev; + snprintf(dev->gd->disk_name, 32, "simdisk%d", which); + set_capacity(dev->gd, 0); + add_disk(dev->gd); + + dev->procfile = proc_create_data(tmp, 0644, procdir, &fops, dev); + return 0; + +out_alloc_disk: + blk_cleanup_queue(dev->queue); + dev->queue = NULL; +out_alloc_queue: + simc_close(dev->fd); + return -EIO; +} + +static int __init simdisk_init(void) +{ + int i; + + if (register_blkdev(simdisk_major, "simdisk") < 0) { + pr_err("SIMDISK: register_blkdev: %d\n", simdisk_major); + return -EIO; + } + pr_info("SIMDISK: major: %d\n", simdisk_major); + + if (n_files > simdisk_count) + simdisk_count = n_files; + if (simdisk_count > MAX_SIMDISK_COUNT) + simdisk_count = MAX_SIMDISK_COUNT; + + sddev = kmalloc(simdisk_count * sizeof(struct simdisk), + GFP_KERNEL); + if (sddev == NULL) + goto out_unregister; + + simdisk_procdir = proc_mkdir("simdisk", 0); + if (simdisk_procdir == NULL) + goto out_free_unregister; + + for (i = 0; i < simdisk_count; ++i) { + if (simdisk_setup(sddev + i, i, simdisk_procdir) == 0) { + if (filename[i] != NULL && filename[i][0] != 0 && + (n_files == 0 || i < n_files)) + simdisk_attach(sddev + i, filename[i]); + } + } + + return 0; + +out_free_unregister: + kfree(sddev); +out_unregister: + unregister_blkdev(simdisk_major, "simdisk"); + return -ENOMEM; +} +module_init(simdisk_init); + +static void simdisk_teardown(struct simdisk *dev, int which, + struct proc_dir_entry *procdir) +{ + char tmp[2] = { '0' + which, 0 }; + + simdisk_detach(dev); + if (dev->gd) + del_gendisk(dev->gd); + if (dev->queue) + blk_cleanup_queue(dev->queue); + remove_proc_entry(tmp, procdir); +} + +static void __exit simdisk_exit(void) +{ + int i; + + for (i = 0; i < simdisk_count; ++i) + simdisk_teardown(sddev + i, i, simdisk_procdir); + remove_proc_entry("simdisk", 0); + kfree(sddev); + unregister_blkdev(simdisk_major, "simdisk"); +} +module_exit(simdisk_exit); + +MODULE_ALIAS_BLOCKDEV_MAJOR(SIMDISK_MAJOR); + +MODULE_LICENSE("GPL"); diff --git a/arch/xtensa/platforms/xt2000/setup.c b/arch/xtensa/platforms/xt2000/setup.c index 9e83940ac26..b90555cb808 100644 --- a/arch/xtensa/platforms/xt2000/setup.c +++ b/arch/xtensa/platforms/xt2000/setup.c @@ -66,13 +66,15 @@ void platform_restart(void) * jump to the reset vector. */ __asm__ __volatile__ ("movi a2, 15\n\t" - "wsr a2, " __stringify(ICOUNTLEVEL) "\n\t" + "wsr a2, icountlevel\n\t" "movi a2, 0\n\t" - "wsr a2, " __stringify(ICOUNT) "\n\t" - "wsr a2, " __stringify(IBREAKENABLE) "\n\t" - "wsr a2, " __stringify(LCOUNT) "\n\t" + "wsr a2, icount\n\t" +#if XCHAL_NUM_IBREAK > 0 + "wsr a2, ibreakenable\n\t" +#endif + "wsr a2, lcount\n\t" "movi a2, 0x1f\n\t" - "wsr a2, " __stringify(PS) "\n\t" + "wsr a2, ps\n\t" "isync\n\t" "jx %0\n\t" : @@ -90,18 +92,8 @@ void __init platform_setup(char** cmdline) /* early initialization */ -extern sysmem_info_t __initdata sysmem; - -void platform_init(bp_tag_t* first) +void __init platform_init(bp_tag_t *first) { - /* Set default memory block if not provided by the bootloader. */ - - if (sysmem.nr_banks == 0) { - sysmem.nr_banks = 1; - sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START; - sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START - + PLATFORM_DEFAULT_MEM_SIZE; - } } /* Heartbeat. Let the LED blink. */ diff --git a/arch/xtensa/platforms/xtfpga/Makefile b/arch/xtensa/platforms/xtfpga/Makefile new file mode 100644 index 00000000000..b9ae206340c --- /dev/null +++ b/arch/xtensa/platforms/xtfpga/Makefile @@ -0,0 +1,9 @@ +# Makefile for the Tensilica xtavnet Emulation Board +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are in the main makefile... + +obj-y = setup.o lcd.o diff --git a/arch/xtensa/platforms/xtfpga/include/platform/hardware.h b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h new file mode 100644 index 00000000000..aeb316b7ff8 --- /dev/null +++ b/arch/xtensa/platforms/xtfpga/include/platform/hardware.h @@ -0,0 +1,65 @@ +/* + * arch/xtensa/platform/xtavnet/include/platform/hardware.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2006 Tensilica Inc. + */ + +/* + * This file contains the hardware configuration of the XTAVNET boards. + */ + +#ifndef __XTENSA_XTAVNET_HARDWARE_H +#define __XTENSA_XTAVNET_HARDWARE_H + +/* Memory configuration. */ + +#define PLATFORM_DEFAULT_MEM_START 0x00000000 +#define PLATFORM_DEFAULT_MEM_SIZE 0x04000000 + +/* Interrupt configuration. */ + +#define PLATFORM_NR_IRQS 10 + +/* Default assignment of LX60 devices to external interrupts. */ + +#ifdef CONFIG_XTENSA_MX +#define DUART16552_INTNUM XCHAL_EXTINT3_NUM +#define OETH_IRQ XCHAL_EXTINT4_NUM +#else +#define DUART16552_INTNUM XCHAL_EXTINT0_NUM +#define OETH_IRQ XCHAL_EXTINT1_NUM +#endif + +/* + * Device addresses and parameters. + */ + +/* UART */ +#define DUART16552_PADDR (XCHAL_KIO_PADDR + 0x0D050020) +/* LCD instruction and data addresses. */ +#define LCD_INSTR_ADDR ((char *)IOADDR(0x0D040000)) +#define LCD_DATA_ADDR ((char *)IOADDR(0x0D040004)) + +/* Misc. */ +#define XTFPGA_FPGAREGS_VADDR IOADDR(0x0D020000) +/* Clock frequency in Hz (read-only): */ +#define XTFPGA_CLKFRQ_VADDR (XTFPGA_FPGAREGS_VADDR + 0x04) +/* Setting of 8 DIP switches: */ +#define DIP_SWITCHES_VADDR (XTFPGA_FPGAREGS_VADDR + 0x0C) +/* Software reset (write 0xdead): */ +#define XTFPGA_SWRST_VADDR (XTFPGA_FPGAREGS_VADDR + 0x10) + +/* OpenCores Ethernet controller: */ + /* regs + RX/TX descriptors */ +#define OETH_REGS_PADDR (XCHAL_KIO_PADDR + 0x0D030000) +#define OETH_REGS_SIZE 0x1000 +#define OETH_SRAMBUFF_PADDR (XCHAL_KIO_PADDR + 0x0D800000) + + /* 5*rx buffs + 5*tx buffs */ +#define OETH_SRAMBUFF_SIZE (5 * 0x600 + 5 * 0x600) + +#endif /* __XTENSA_XTAVNET_HARDWARE_H */ diff --git a/arch/xtensa/platforms/xtfpga/include/platform/lcd.h b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h new file mode 100644 index 00000000000..0e435645af5 --- /dev/null +++ b/arch/xtensa/platforms/xtfpga/include/platform/lcd.h @@ -0,0 +1,20 @@ +/* + * arch/xtensa/platform/xtavnet/include/platform/lcd.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001, 2006 Tensilica Inc. + */ + +#ifndef __XTENSA_XTAVNET_LCD_H +#define __XTENSA_XTAVNET_LCD_H + +/* Display string STR at position POS on the LCD. */ +void lcd_disp_at_pos(char *str, unsigned char pos); + +/* Shift the contents of the LCD display left or right. */ +void lcd_shiftleft(void); +void lcd_shiftright(void); +#endif diff --git a/arch/xtensa/platforms/xtfpga/include/platform/serial.h b/arch/xtensa/platforms/xtfpga/include/platform/serial.h new file mode 100644 index 00000000000..14d8f7beebf --- /dev/null +++ b/arch/xtensa/platforms/xtfpga/include/platform/serial.h @@ -0,0 +1,18 @@ +/* + * arch/xtensa/platform/xtavnet/include/platform/serial.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001, 2006 Tensilica Inc. + */ + +#ifndef __ASM_XTENSA_XTAVNET_SERIAL_H +#define __ASM_XTENSA_XTAVNET_SERIAL_H + +#include <platform/hardware.h> + +#define BASE_BAUD (*(long *)XTFPGA_CLKFRQ_VADDR / 16) + +#endif /* __ASM_XTENSA_XTAVNET_SERIAL_H */ diff --git a/arch/xtensa/platforms/xtfpga/lcd.c b/arch/xtensa/platforms/xtfpga/lcd.c new file mode 100644 index 00000000000..2872301598d --- /dev/null +++ b/arch/xtensa/platforms/xtfpga/lcd.c @@ -0,0 +1,76 @@ +/* + * Driver for the LCD display on the Tensilica LX60 Board. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001, 2006 Tensilica Inc. + */ + +/* + * + * FIXME: this code is from the examples from the LX60 user guide. + * + * The lcd_pause function does busy waiting, which is probably not + * great. Maybe the code could be changed to use kernel timers, or + * change the hardware to not need to wait. + */ + +#include <linux/init.h> +#include <linux/io.h> + +#include <platform/hardware.h> +#include <platform/lcd.h> +#include <linux/delay.h> + +#define LCD_PAUSE_ITERATIONS 4000 +#define LCD_CLEAR 0x1 +#define LCD_DISPLAY_ON 0xc + +/* 8bit and 2 lines display */ +#define LCD_DISPLAY_MODE8BIT 0x38 +#define LCD_DISPLAY_POS 0x80 +#define LCD_SHIFT_LEFT 0x18 +#define LCD_SHIFT_RIGHT 0x1c + +static int __init lcd_init(void) +{ + *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; + mdelay(5); + *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; + udelay(200); + *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT; + udelay(50); + *LCD_INSTR_ADDR = LCD_DISPLAY_ON; + udelay(50); + *LCD_INSTR_ADDR = LCD_CLEAR; + mdelay(10); + lcd_disp_at_pos("XTENSA LINUX", 0); + return 0; +} + +void lcd_disp_at_pos(char *str, unsigned char pos) +{ + *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos; + udelay(100); + while (*str != 0) { + *LCD_DATA_ADDR = *str; + udelay(200); + str++; + } +} + +void lcd_shiftleft(void) +{ + *LCD_INSTR_ADDR = LCD_SHIFT_LEFT; + udelay(50); +} + +void lcd_shiftright(void) +{ + *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT; + udelay(50); +} + +arch_initcall(lcd_init); diff --git a/arch/xtensa/platforms/xtfpga/setup.c b/arch/xtensa/platforms/xtfpga/setup.c new file mode 100644 index 00000000000..57fd08b36f5 --- /dev/null +++ b/arch/xtensa/platforms/xtfpga/setup.c @@ -0,0 +1,303 @@ +/* + * + * arch/xtensa/platform/xtavnet/setup.c + * + * ... + * + * Authors: Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com> + * + * Copyright 2001 - 2006 Tensilica Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/reboot.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/of.h> + +#include <asm/timex.h> +#include <asm/processor.h> +#include <asm/platform.h> +#include <asm/bootparam.h> +#include <platform/lcd.h> +#include <platform/hardware.h> + +void platform_halt(void) +{ + lcd_disp_at_pos(" HALT ", 0); + local_irq_disable(); + while (1) + cpu_relax(); +} + +void platform_power_off(void) +{ + lcd_disp_at_pos("POWEROFF", 0); + local_irq_disable(); + while (1) + cpu_relax(); +} + +void platform_restart(void) +{ + /* Flush and reset the mmu, simulate a processor reset, and + * jump to the reset vector. */ + + + __asm__ __volatile__ ("movi a2, 15\n\t" + "wsr a2, icountlevel\n\t" + "movi a2, 0\n\t" + "wsr a2, icount\n\t" +#if XCHAL_NUM_IBREAK > 0 + "wsr a2, ibreakenable\n\t" +#endif + "wsr a2, lcount\n\t" + "movi a2, 0x1f\n\t" + "wsr a2, ps\n\t" + "isync\n\t" + "jx %0\n\t" + : + : "a" (XCHAL_RESET_VECTOR_VADDR) + : "a2" + ); + + /* control never gets here */ +} + +void __init platform_setup(char **cmdline) +{ +} + +#ifdef CONFIG_OF + +static void __init update_clock_frequency(struct device_node *node) +{ + struct property *newfreq; + u32 freq; + + if (!of_property_read_u32(node, "clock-frequency", &freq) && freq != 0) + return; + + newfreq = kzalloc(sizeof(*newfreq) + sizeof(u32), GFP_KERNEL); + if (!newfreq) + return; + newfreq->value = newfreq + 1; + newfreq->length = sizeof(freq); + newfreq->name = kstrdup("clock-frequency", GFP_KERNEL); + if (!newfreq->name) { + kfree(newfreq); + return; + } + + *(u32 *)newfreq->value = cpu_to_be32(*(u32 *)XTFPGA_CLKFRQ_VADDR); + of_update_property(node, newfreq); +} + +#define MAC_LEN 6 +static void __init update_local_mac(struct device_node *node) +{ + struct property *newmac; + const u8* macaddr; + int prop_len; + + macaddr = of_get_property(node, "local-mac-address", &prop_len); + if (macaddr == NULL || prop_len != MAC_LEN) + return; + + newmac = kzalloc(sizeof(*newmac) + MAC_LEN, GFP_KERNEL); + if (newmac == NULL) + return; + + newmac->value = newmac + 1; + newmac->length = MAC_LEN; + newmac->name = kstrdup("local-mac-address", GFP_KERNEL); + if (newmac->name == NULL) { + kfree(newmac); + return; + } + + memcpy(newmac->value, macaddr, MAC_LEN); + ((u8*)newmac->value)[5] = (*(u32*)DIP_SWITCHES_VADDR) & 0x3f; + of_update_property(node, newmac); +} + +static int __init machine_setup(void) +{ + struct device_node *clock; + struct device_node *eth = NULL; + + for_each_node_by_name(clock, "main-oscillator") + update_clock_frequency(clock); + + if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc"))) + update_local_mac(eth); + return 0; +} +arch_initcall(machine_setup); + +#endif + +/* early initialization */ + +void __init platform_init(bp_tag_t *first) +{ +} + +/* Heartbeat. */ + +void platform_heartbeat(void) +{ +} + +#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT + +void __init platform_calibrate_ccount(void) +{ + long clk_freq = 0; +#ifdef CONFIG_OF + struct device_node *cpu = + of_find_compatible_node(NULL, NULL, "cdns,xtensa-cpu"); + if (cpu) { + u32 freq; + update_clock_frequency(cpu); + if (!of_property_read_u32(cpu, "clock-frequency", &freq)) + clk_freq = freq; + } +#endif + if (!clk_freq) + clk_freq = *(long *)XTFPGA_CLKFRQ_VADDR; + + ccount_freq = clk_freq; +} + +#endif + +#ifndef CONFIG_OF + +#include <linux/serial_8250.h> +#include <linux/if.h> +#include <net/ethoc.h> + +/*---------------------------------------------------------------------------- + * Ethernet -- OpenCores Ethernet MAC (ethoc driver) + */ + +static struct resource ethoc_res[] = { + [0] = { /* register space */ + .start = OETH_REGS_PADDR, + .end = OETH_REGS_PADDR + OETH_REGS_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { /* buffer space */ + .start = OETH_SRAMBUFF_PADDR, + .end = OETH_SRAMBUFF_PADDR + OETH_SRAMBUFF_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + [2] = { /* IRQ number */ + .start = OETH_IRQ, + .end = OETH_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct ethoc_platform_data ethoc_pdata = { + /* + * The MAC address for these boards is 00:50:c2:13:6f:xx. + * The last byte (here as zero) is read from the DIP switches on the + * board. + */ + .hwaddr = { 0x00, 0x50, 0xc2, 0x13, 0x6f, 0 }, + .phy_id = -1, +}; + +static struct platform_device ethoc_device = { + .name = "ethoc", + .id = -1, + .num_resources = ARRAY_SIZE(ethoc_res), + .resource = ethoc_res, + .dev = { + .platform_data = ðoc_pdata, + }, +}; + +/*---------------------------------------------------------------------------- + * UART + */ + +static struct resource serial_resource = { + .start = DUART16552_PADDR, + .end = DUART16552_PADDR + 0x1f, + .flags = IORESOURCE_MEM, +}; + +static struct plat_serial8250_port serial_platform_data[] = { + [0] = { + .mapbase = DUART16552_PADDR, + .irq = DUART16552_INTNUM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_IOREMAP, + .iotype = UPIO_MEM32, + .regshift = 2, + .uartclk = 0, /* set in xtavnet_init() */ + }, + { }, +}; + +static struct platform_device xtavnet_uart = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = serial_platform_data, + }, + .num_resources = 1, + .resource = &serial_resource, +}; + +/* platform devices */ +static struct platform_device *platform_devices[] __initdata = { + ðoc_device, + &xtavnet_uart, +}; + + +static int __init xtavnet_init(void) +{ + /* Ethernet MAC address. */ + ethoc_pdata.hwaddr[5] = *(u32 *)DIP_SWITCHES_VADDR; + + /* Clock rate varies among FPGA bitstreams; board specific FPGA register + * reports the actual clock rate. + */ + serial_platform_data[0].uartclk = *(long *)XTFPGA_CLKFRQ_VADDR; + + + /* register platform devices */ + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + + /* ETHOC driver is a bit quiet; at least display Ethernet MAC, so user + * knows whether they set it correctly on the DIP switches. + */ + pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr); + ethoc_pdata.eth_clkfreq = *(long *)XTFPGA_CLKFRQ_VADDR; + + return 0; +} + +/* + * Register to be done during do_initcalls(). + */ +arch_initcall(xtavnet_init); + +#endif /* CONFIG_OF */ |
