diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-22 15:38:31 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-22 15:38:31 -0400 |
| commit | f39cf0b783b3f402ddf1eb6a09234b5bfe34bb2a (patch) | |
| tree | 6ac105287f433be5be65b14f1246a23e368c3ae2 | |
| parent | 59ef7a83f1127038a433464597df02e2dc9540e7 (diff) | |
| parent | aafd1255d08fb26cab87d1b28ff35a15bdb2ed68 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/czankel/xtensa-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/czankel/xtensa-2.6:
xtensa: enable m41t80 driver in s6105_defconfig
xtensa: add m41t62 rtc to s6105 platform
xtensa: enable s6gmac in s6105_defconfig
xtensa: s6105 specific configuration for s6gmac
s6gmac: xtensa s6000 on-chip ethernet driver
xtensa: support s6000 gpio irqs and alternate function selection
xtensa: s6000 dma engine support
xtensa: allow variant to initialize own irq chips
xtensa: cache inquiry and unaligned cache handling functions
| -rw-r--r-- | arch/xtensa/configs/s6105_defconfig | 105 | ||||
| -rw-r--r-- | arch/xtensa/include/asm/cacheflush.h | 95 | ||||
| -rw-r--r-- | arch/xtensa/include/asm/gpio.h | 8 | ||||
| -rw-r--r-- | arch/xtensa/include/asm/irq.h | 12 | ||||
| -rw-r--r-- | arch/xtensa/kernel/irq.c | 2 | ||||
| -rw-r--r-- | arch/xtensa/platforms/s6105/device.c | 94 | ||||
| -rw-r--r-- | arch/xtensa/platforms/s6105/setup.c | 11 | ||||
| -rw-r--r-- | arch/xtensa/variants/s6000/Makefile | 2 | ||||
| -rw-r--r-- | arch/xtensa/variants/s6000/dmac.c | 173 | ||||
| -rw-r--r-- | arch/xtensa/variants/s6000/gpio.c | 163 | ||||
| -rw-r--r-- | arch/xtensa/variants/s6000/include/variant/dmac.h | 387 | ||||
| -rw-r--r-- | arch/xtensa/variants/s6000/include/variant/gpio.h | 2 | ||||
| -rw-r--r-- | arch/xtensa/variants/s6000/include/variant/irq.h | 6 | ||||
| -rw-r--r-- | drivers/net/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/net/Makefile | 1 | ||||
| -rw-r--r-- | drivers/net/s6gmac.c | 1073 |
16 files changed, 2129 insertions, 16 deletions
diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig index 768bee006037..bb84fbc9921f 100644 --- a/arch/xtensa/configs/s6105_defconfig +++ b/arch/xtensa/configs/s6105_defconfig | |||
| @@ -263,7 +263,54 @@ CONFIG_HAVE_IDE=y | |||
| 263 | # CONFIG_SCSI_NETLINK is not set | 263 | # CONFIG_SCSI_NETLINK is not set |
| 264 | # CONFIG_ATA is not set | 264 | # CONFIG_ATA is not set |
| 265 | # CONFIG_MD is not set | 265 | # CONFIG_MD is not set |
| 266 | # CONFIG_NETDEVICES is not set | 266 | CONFIG_NETDEVICES=y |
| 267 | # CONFIG_DUMMY is not set | ||
| 268 | # CONFIG_BONDING is not set | ||
| 269 | # CONFIG_MACVLAN is not set | ||
| 270 | # CONFIG_EQUALIZER is not set | ||
| 271 | # CONFIG_TUN is not set | ||
| 272 | # CONFIG_VETH is not set | ||
| 273 | CONFIG_PHYLIB=y | ||
| 274 | |||
| 275 | # | ||
| 276 | # MII PHY device drivers | ||
| 277 | # | ||
| 278 | # CONFIG_MARVELL_PHY is not set | ||
| 279 | # CONFIG_DAVICOM_PHY is not set | ||
| 280 | # CONFIG_QSEMI_PHY is not set | ||
| 281 | # CONFIG_LXT_PHY is not set | ||
| 282 | # CONFIG_CICADA_PHY is not set | ||
| 283 | # CONFIG_VITESSE_PHY is not set | ||
| 284 | CONFIG_SMSC_PHY=y | ||
| 285 | # CONFIG_BROADCOM_PHY is not set | ||
| 286 | # CONFIG_ICPLUS_PHY is not set | ||
| 287 | # CONFIG_REALTEK_PHY is not set | ||
| 288 | # CONFIG_NATIONAL_PHY is not set | ||
| 289 | # CONFIG_STE10XP is not set | ||
| 290 | # CONFIG_LSI_ET1011C_PHY is not set | ||
| 291 | # CONFIG_FIXED_PHY is not set | ||
| 292 | # CONFIG_MDIO_BITBANG is not set | ||
| 293 | # CONFIG_NET_ETHERNET is not set | ||
| 294 | CONFIG_NETDEV_1000=y | ||
| 295 | CONFIG_S6GMAC=y | ||
| 296 | # CONFIG_NETDEV_10000 is not set | ||
| 297 | |||
| 298 | # | ||
| 299 | # Wireless LAN | ||
| 300 | # | ||
| 301 | # CONFIG_WLAN_PRE80211 is not set | ||
| 302 | # CONFIG_WLAN_80211 is not set | ||
| 303 | # CONFIG_IWLWIFI_LEDS is not set | ||
| 304 | |||
| 305 | # | ||
| 306 | # Enable WiMAX (Networking options) to see the WiMAX drivers | ||
| 307 | # | ||
| 308 | # CONFIG_WAN is not set | ||
| 309 | # CONFIG_PPP is not set | ||
| 310 | # CONFIG_SLIP is not set | ||
| 311 | # CONFIG_NETCONSOLE is not set | ||
| 312 | # CONFIG_NETPOLL is not set | ||
| 313 | # CONFIG_NET_POLL_CONTROLLER is not set | ||
| 267 | # CONFIG_ISDN is not set | 314 | # CONFIG_ISDN is not set |
| 268 | # CONFIG_PHONE is not set | 315 | # CONFIG_PHONE is not set |
| 269 | 316 | ||
| @@ -304,8 +351,6 @@ CONFIG_UNIX98_PTYS=y | |||
| 304 | # CONFIG_LEGACY_PTYS is not set | 351 | # CONFIG_LEGACY_PTYS is not set |
| 305 | # CONFIG_IPMI_HANDLER is not set | 352 | # CONFIG_IPMI_HANDLER is not set |
| 306 | # CONFIG_HW_RANDOM is not set | 353 | # CONFIG_HW_RANDOM is not set |
| 307 | # CONFIG_RTC is not set | ||
| 308 | # CONFIG_GEN_RTC is not set | ||
| 309 | # CONFIG_R3964 is not set | 354 | # CONFIG_R3964 is not set |
| 310 | # CONFIG_RAW_DRIVER is not set | 355 | # CONFIG_RAW_DRIVER is not set |
| 311 | # CONFIG_TCG_TPM is not set | 356 | # CONFIG_TCG_TPM is not set |
| @@ -387,7 +432,59 @@ CONFIG_SSB_POSSIBLE=y | |||
| 387 | # CONFIG_MEMSTICK is not set | 432 | # CONFIG_MEMSTICK is not set |
| 388 | # CONFIG_NEW_LEDS is not set | 433 | # CONFIG_NEW_LEDS is not set |
| 389 | # CONFIG_ACCESSIBILITY is not set | 434 | # CONFIG_ACCESSIBILITY is not set |
| 390 | # CONFIG_RTC_CLASS is not set | 435 | CONFIG_RTC_LIB=y |
| 436 | CONFIG_RTC_CLASS=y | ||
| 437 | CONFIG_RTC_HCTOSYS=y | ||
| 438 | CONFIG_RTC_HCTOSYS_DEVICE="rtc0" | ||
| 439 | # CONFIG_RTC_DEBUG is not set | ||
| 440 | |||
| 441 | # | ||
| 442 | # RTC interfaces | ||
| 443 | # | ||
| 444 | # CONFIG_RTC_INTF_SYSFS is not set | ||
| 445 | # CONFIG_RTC_INTF_PROC is not set | ||
| 446 | # CONFIG_RTC_INTF_DEV is not set | ||
| 447 | # CONFIG_RTC_DRV_TEST is not set | ||
| 448 | |||
| 449 | # | ||
| 450 | # I2C RTC drivers | ||
| 451 | # | ||
| 452 | # CONFIG_RTC_DRV_DS1307 is not set | ||
| 453 | # CONFIG_RTC_DRV_DS1374 is not set | ||
| 454 | # CONFIG_RTC_DRV_DS1672 is not set | ||
| 455 | # CONFIG_RTC_DRV_MAX6900 is not set | ||
| 456 | # CONFIG_RTC_DRV_RS5C372 is not set | ||
| 457 | # CONFIG_RTC_DRV_ISL1208 is not set | ||
| 458 | # CONFIG_RTC_DRV_X1205 is not set | ||
| 459 | # CONFIG_RTC_DRV_PCF8563 is not set | ||
| 460 | # CONFIG_RTC_DRV_PCF8583 is not set | ||
| 461 | CONFIG_RTC_DRV_M41T80=y | ||
| 462 | # CONFIG_RTC_DRV_M41T80_WDT is not set | ||
| 463 | # CONFIG_RTC_DRV_S35390A is not set | ||
| 464 | # CONFIG_RTC_DRV_FM3130 is not set | ||
| 465 | # CONFIG_RTC_DRV_RX8581 is not set | ||
| 466 | |||
| 467 | # | ||
| 468 | # SPI RTC drivers | ||
| 469 | # | ||
| 470 | |||
| 471 | # | ||
| 472 | # Platform RTC drivers | ||
| 473 | # | ||
| 474 | # CONFIG_RTC_DRV_DS1286 is not set | ||
| 475 | # CONFIG_RTC_DRV_DS1511 is not set | ||
| 476 | # CONFIG_RTC_DRV_DS1553 is not set | ||
| 477 | # CONFIG_RTC_DRV_DS1742 is not set | ||
| 478 | # CONFIG_RTC_DRV_STK17TA8 is not set | ||
| 479 | # CONFIG_RTC_DRV_M48T86 is not set | ||
| 480 | # CONFIG_RTC_DRV_M48T35 is not set | ||
| 481 | # CONFIG_RTC_DRV_M48T59 is not set | ||
| 482 | # CONFIG_RTC_DRV_BQ4802 is not set | ||
| 483 | # CONFIG_RTC_DRV_V3020 is not set | ||
| 484 | |||
| 485 | # | ||
| 486 | # on-CPU RTC drivers | ||
| 487 | # | ||
| 391 | # CONFIG_DMADEVICES is not set | 488 | # CONFIG_DMADEVICES is not set |
| 392 | # CONFIG_UIO is not set | 489 | # CONFIG_UIO is not set |
| 393 | # CONFIG_STAGING is not set | 490 | # CONFIG_STAGING is not set |
diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h index 8fc1c0c8de07..b7b8fbe47c77 100644 --- a/arch/xtensa/include/asm/cacheflush.h +++ b/arch/xtensa/include/asm/cacheflush.h | |||
| @@ -155,5 +155,100 @@ extern void copy_from_user_page(struct vm_area_struct*, struct page*, | |||
| 155 | 155 | ||
| 156 | #endif | 156 | #endif |
| 157 | 157 | ||
| 158 | #define XTENSA_CACHEBLK_LOG2 29 | ||
| 159 | #define XTENSA_CACHEBLK_SIZE (1 << XTENSA_CACHEBLK_LOG2) | ||
| 160 | #define XTENSA_CACHEBLK_MASK (7 << XTENSA_CACHEBLK_LOG2) | ||
| 161 | |||
| 162 | #if XCHAL_HAVE_CACHEATTR | ||
| 163 | static inline u32 xtensa_get_cacheattr(void) | ||
| 164 | { | ||
| 165 | u32 r; | ||
| 166 | asm volatile(" rsr %0, CACHEATTR" : "=a"(r)); | ||
| 167 | return r; | ||
| 168 | } | ||
| 169 | |||
| 170 | static inline u32 xtensa_get_dtlb1(u32 addr) | ||
| 171 | { | ||
| 172 | u32 r = addr & XTENSA_CACHEBLK_MASK; | ||
| 173 | return r | ((xtensa_get_cacheattr() >> (r >> (XTENSA_CACHEBLK_LOG2-2))) | ||
| 174 | & 0xF); | ||
| 175 | } | ||
| 176 | #else | ||
| 177 | static inline u32 xtensa_get_dtlb1(u32 addr) | ||
| 178 | { | ||
| 179 | u32 r; | ||
| 180 | asm volatile(" rdtlb1 %0, %1" : "=a"(r) : "a"(addr)); | ||
| 181 | asm volatile(" dsync"); | ||
| 182 | return r; | ||
| 183 | } | ||
| 184 | |||
| 185 | static inline u32 xtensa_get_cacheattr(void) | ||
| 186 | { | ||
| 187 | u32 r = 0; | ||
| 188 | u32 a = 0; | ||
| 189 | do { | ||
| 190 | a -= XTENSA_CACHEBLK_SIZE; | ||
| 191 | r = (r << 4) | (xtensa_get_dtlb1(a) & 0xF); | ||
| 192 | } while (a); | ||
| 193 | return r; | ||
| 194 | } | ||
| 195 | #endif | ||
| 196 | |||
| 197 | static inline int xtensa_need_flush_dma_source(u32 addr) | ||
| 198 | { | ||
| 199 | return (xtensa_get_dtlb1(addr) & ((1 << XCHAL_CA_BITS) - 1)) >= 4; | ||
| 200 | } | ||
| 201 | |||
| 202 | static inline int xtensa_need_invalidate_dma_destination(u32 addr) | ||
| 203 | { | ||
| 204 | return (xtensa_get_dtlb1(addr) & ((1 << XCHAL_CA_BITS) - 1)) != 2; | ||
| 205 | } | ||
| 206 | |||
| 207 | static inline void flush_dcache_unaligned(u32 addr, u32 size) | ||
| 208 | { | ||
| 209 | u32 cnt; | ||
| 210 | if (size) { | ||
| 211 | cnt = (size + ((XCHAL_DCACHE_LINESIZE - 1) & addr) | ||
| 212 | + XCHAL_DCACHE_LINESIZE - 1) / XCHAL_DCACHE_LINESIZE; | ||
| 213 | while (cnt--) { | ||
| 214 | asm volatile(" dhwb %0, 0" : : "a"(addr)); | ||
| 215 | addr += XCHAL_DCACHE_LINESIZE; | ||
| 216 | } | ||
| 217 | asm volatile(" dsync"); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | static inline void invalidate_dcache_unaligned(u32 addr, u32 size) | ||
| 222 | { | ||
| 223 | int cnt; | ||
| 224 | if (size) { | ||
| 225 | asm volatile(" dhwbi %0, 0 ;" : : "a"(addr)); | ||
| 226 | cnt = (size + ((XCHAL_DCACHE_LINESIZE - 1) & addr) | ||
| 227 | - XCHAL_DCACHE_LINESIZE - 1) / XCHAL_DCACHE_LINESIZE; | ||
| 228 | while (cnt-- > 0) { | ||
| 229 | asm volatile(" dhi %0, %1" : : "a"(addr), | ||
| 230 | "n"(XCHAL_DCACHE_LINESIZE)); | ||
| 231 | addr += XCHAL_DCACHE_LINESIZE; | ||
| 232 | } | ||
| 233 | asm volatile(" dhwbi %0, %1" : : "a"(addr), | ||
| 234 | "n"(XCHAL_DCACHE_LINESIZE)); | ||
| 235 | asm volatile(" dsync"); | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | static inline void flush_invalidate_dcache_unaligned(u32 addr, u32 size) | ||
| 240 | { | ||
| 241 | u32 cnt; | ||
| 242 | if (size) { | ||
| 243 | cnt = (size + ((XCHAL_DCACHE_LINESIZE - 1) & addr) | ||
| 244 | + XCHAL_DCACHE_LINESIZE - 1) / XCHAL_DCACHE_LINESIZE; | ||
| 245 | while (cnt--) { | ||
| 246 | asm volatile(" dhwbi %0, 0" : : "a"(addr)); | ||
| 247 | addr += XCHAL_DCACHE_LINESIZE; | ||
| 248 | } | ||
| 249 | asm volatile(" dsync"); | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 158 | #endif /* __KERNEL__ */ | 253 | #endif /* __KERNEL__ */ |
| 159 | #endif /* _XTENSA_CACHEFLUSH_H */ | 254 | #endif /* _XTENSA_CACHEFLUSH_H */ |
diff --git a/arch/xtensa/include/asm/gpio.h b/arch/xtensa/include/asm/gpio.h index 0763b0763960..a8c9fc46c790 100644 --- a/arch/xtensa/include/asm/gpio.h +++ b/arch/xtensa/include/asm/gpio.h | |||
| @@ -38,14 +38,14 @@ static inline int gpio_cansleep(unsigned int gpio) | |||
| 38 | return __gpio_cansleep(gpio); | 38 | return __gpio_cansleep(gpio); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | /* | ||
| 42 | * Not implemented, yet. | ||
| 43 | */ | ||
| 44 | static inline int gpio_to_irq(unsigned int gpio) | 41 | static inline int gpio_to_irq(unsigned int gpio) |
| 45 | { | 42 | { |
| 46 | return -ENOSYS; | 43 | return __gpio_to_irq(gpio); |
| 47 | } | 44 | } |
| 48 | 45 | ||
| 46 | /* | ||
| 47 | * Not implemented, yet. | ||
| 48 | */ | ||
| 49 | static inline int irq_to_gpio(unsigned int irq) | 49 | static inline int irq_to_gpio(unsigned int irq) |
| 50 | { | 50 | { |
| 51 | return -EINVAL; | 51 | return -EINVAL; |
diff --git a/arch/xtensa/include/asm/irq.h b/arch/xtensa/include/asm/irq.h index dfac82dc52ad..4c0ccc9c4f4c 100644 --- a/arch/xtensa/include/asm/irq.h +++ b/arch/xtensa/include/asm/irq.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #ifndef _XTENSA_IRQ_H | 11 | #ifndef _XTENSA_IRQ_H |
| 12 | #define _XTENSA_IRQ_H | 12 | #define _XTENSA_IRQ_H |
| 13 | 13 | ||
| 14 | #include <linux/init.h> | ||
| 14 | #include <platform/hardware.h> | 15 | #include <platform/hardware.h> |
| 15 | #include <variant/core.h> | 16 | #include <variant/core.h> |
| 16 | 17 | ||
| @@ -21,11 +22,20 @@ static inline void variant_irq_enable(unsigned int irq) { } | |||
| 21 | static inline void variant_irq_disable(unsigned int irq) { } | 22 | static inline void variant_irq_disable(unsigned int irq) { } |
| 22 | #endif | 23 | #endif |
| 23 | 24 | ||
| 25 | #ifndef VARIANT_NR_IRQS | ||
| 26 | # define VARIANT_NR_IRQS 0 | ||
| 27 | #endif | ||
| 24 | #ifndef PLATFORM_NR_IRQS | 28 | #ifndef PLATFORM_NR_IRQS |
| 25 | # define PLATFORM_NR_IRQS 0 | 29 | # define PLATFORM_NR_IRQS 0 |
| 26 | #endif | 30 | #endif |
| 27 | #define XTENSA_NR_IRQS XCHAL_NUM_INTERRUPTS | 31 | #define XTENSA_NR_IRQS XCHAL_NUM_INTERRUPTS |
| 28 | #define NR_IRQS (XTENSA_NR_IRQS + PLATFORM_NR_IRQS) | 32 | #define NR_IRQS (XTENSA_NR_IRQS + VARIANT_NR_IRQS + PLATFORM_NR_IRQS) |
| 33 | |||
| 34 | #if VARIANT_NR_IRQS == 0 | ||
| 35 | static inline void variant_init_irq(void) { } | ||
| 36 | #else | ||
| 37 | void variant_init_irq(void) __init; | ||
| 38 | #endif | ||
| 29 | 39 | ||
| 30 | static __inline__ int irq_canonicalize(int irq) | 40 | static __inline__ int irq_canonicalize(int irq) |
| 31 | { | 41 | { |
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c index a36c85edd045..a1badb32fcda 100644 --- a/arch/xtensa/kernel/irq.c +++ b/arch/xtensa/kernel/irq.c | |||
| @@ -197,4 +197,6 @@ void __init init_IRQ(void) | |||
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | cached_irq_mask = 0; | 199 | cached_irq_mask = 0; |
| 200 | |||
| 201 | variant_init_irq(); | ||
| 200 | } | 202 | } |
diff --git a/arch/xtensa/platforms/s6105/device.c b/arch/xtensa/platforms/s6105/device.c index 78b08be5a92d..65333ffefb07 100644 --- a/arch/xtensa/platforms/s6105/device.c +++ b/arch/xtensa/platforms/s6105/device.c | |||
| @@ -5,14 +5,27 @@ | |||
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| 8 | #include <linux/gpio.h> | ||
| 8 | #include <linux/init.h> | 9 | #include <linux/init.h> |
| 10 | #include <linux/irq.h> | ||
| 11 | #include <linux/phy.h> | ||
| 9 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
| 10 | #include <linux/serial.h> | 13 | #include <linux/serial.h> |
| 11 | #include <linux/serial_8250.h> | 14 | #include <linux/serial_8250.h> |
| 12 | 15 | ||
| 13 | #include <variant/hardware.h> | 16 | #include <variant/hardware.h> |
| 17 | #include <variant/dmac.h> | ||
| 14 | 18 | ||
| 19 | #include <platform/gpio.h> | ||
| 20 | |||
| 21 | #define GPIO3_INTNUM 3 | ||
| 15 | #define UART_INTNUM 4 | 22 | #define UART_INTNUM 4 |
| 23 | #define GMAC_INTNUM 5 | ||
| 24 | |||
| 25 | static const signed char gpio3_irq_mappings[] = { | ||
| 26 | S6_INTC_GPIO(3), | ||
| 27 | -1 | ||
| 28 | }; | ||
| 16 | 29 | ||
| 17 | static const signed char uart_irq_mappings[] = { | 30 | static const signed char uart_irq_mappings[] = { |
| 18 | S6_INTC_UART(0), | 31 | S6_INTC_UART(0), |
| @@ -20,8 +33,18 @@ static const signed char uart_irq_mappings[] = { | |||
| 20 | -1, | 33 | -1, |
| 21 | }; | 34 | }; |
| 22 | 35 | ||
| 36 | static const signed char gmac_irq_mappings[] = { | ||
| 37 | S6_INTC_GMAC_STAT, | ||
| 38 | S6_INTC_GMAC_ERR, | ||
| 39 | S6_INTC_DMA_HOSTTERMCNT(0), | ||
| 40 | S6_INTC_DMA_HOSTTERMCNT(1), | ||
| 41 | -1 | ||
| 42 | }; | ||
| 43 | |||
| 23 | const signed char *platform_irq_mappings[NR_IRQS] = { | 44 | const signed char *platform_irq_mappings[NR_IRQS] = { |
| 45 | [GPIO3_INTNUM] = gpio3_irq_mappings, | ||
| 24 | [UART_INTNUM] = uart_irq_mappings, | 46 | [UART_INTNUM] = uart_irq_mappings, |
| 47 | [GMAC_INTNUM] = gmac_irq_mappings, | ||
| 25 | }; | 48 | }; |
| 26 | 49 | ||
| 27 | static struct plat_serial8250_port serial_platform_data[] = { | 50 | static struct plat_serial8250_port serial_platform_data[] = { |
| @@ -46,6 +69,66 @@ static struct plat_serial8250_port serial_platform_data[] = { | |||
| 46 | { }, | 69 | { }, |
| 47 | }; | 70 | }; |
| 48 | 71 | ||
| 72 | static struct resource s6_gmac_resource[] = { | ||
| 73 | { | ||
| 74 | .name = "mem", | ||
| 75 | .start = (resource_size_t)S6_REG_GMAC, | ||
| 76 | .end = (resource_size_t)S6_REG_GMAC + 0x10000 - 1, | ||
| 77 | .flags = IORESOURCE_MEM, | ||
| 78 | }, | ||
| 79 | { | ||
| 80 | .name = "dma", | ||
| 81 | .start = (resource_size_t) | ||
| 82 | DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACTX), | ||
| 83 | .end = (resource_size_t) | ||
| 84 | DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACTX) + 0x100 - 1, | ||
| 85 | .flags = IORESOURCE_DMA, | ||
| 86 | }, | ||
| 87 | { | ||
| 88 | .name = "dma", | ||
| 89 | .start = (resource_size_t) | ||
| 90 | DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACRX), | ||
| 91 | .end = (resource_size_t) | ||
| 92 | DMA_CHNL(S6_REG_HIFDMA, S6_HIFDMA_GMACRX) + 0x100 - 1, | ||
| 93 | .flags = IORESOURCE_DMA, | ||
| 94 | }, | ||
| 95 | { | ||
| 96 | .name = "io", | ||
| 97 | .start = (resource_size_t)S6_MEM_GMAC, | ||
| 98 | .end = (resource_size_t)S6_MEM_GMAC + 0x2000000 - 1, | ||
| 99 | .flags = IORESOURCE_IO, | ||
| 100 | }, | ||
| 101 | { | ||
| 102 | .name = "irq", | ||
| 103 | .start = (resource_size_t)GMAC_INTNUM, | ||
| 104 | .flags = IORESOURCE_IRQ, | ||
| 105 | }, | ||
| 106 | { | ||
| 107 | .name = "irq", | ||
| 108 | .start = (resource_size_t)PHY_POLL, | ||
| 109 | .flags = IORESOURCE_IRQ, | ||
| 110 | }, | ||
| 111 | }; | ||
| 112 | |||
| 113 | static int __init prepare_phy_irq(int pin) | ||
| 114 | { | ||
| 115 | int irq; | ||
| 116 | if (gpio_request(pin, "s6gmac_phy") < 0) | ||
| 117 | goto fail; | ||
| 118 | if (gpio_direction_input(pin) < 0) | ||
| 119 | goto free; | ||
| 120 | irq = gpio_to_irq(pin); | ||
| 121 | if (irq < 0) | ||
| 122 | goto free; | ||
| 123 | if (set_irq_type(irq, IRQ_TYPE_LEVEL_LOW) < 0) | ||
| 124 | goto free; | ||
| 125 | return irq; | ||
| 126 | free: | ||
| 127 | gpio_free(pin); | ||
| 128 | fail: | ||
| 129 | return PHY_POLL; | ||
| 130 | } | ||
| 131 | |||
| 49 | static struct platform_device platform_devices[] = { | 132 | static struct platform_device platform_devices[] = { |
| 50 | { | 133 | { |
| 51 | .name = "serial8250", | 134 | .name = "serial8250", |
| @@ -54,12 +137,23 @@ static struct platform_device platform_devices[] = { | |||
| 54 | .platform_data = serial_platform_data, | 137 | .platform_data = serial_platform_data, |
| 55 | }, | 138 | }, |
| 56 | }, | 139 | }, |
| 140 | { | ||
| 141 | .name = "s6gmac", | ||
| 142 | .id = 0, | ||
| 143 | .resource = s6_gmac_resource, | ||
| 144 | .num_resources = ARRAY_SIZE(s6_gmac_resource), | ||
| 145 | }, | ||
| 146 | { | ||
| 147 | I2C_BOARD_INFO("m41t62", S6I2C_ADDR_M41T62), | ||
| 148 | }, | ||
| 57 | }; | 149 | }; |
| 58 | 150 | ||
| 59 | static int __init device_init(void) | 151 | static int __init device_init(void) |
| 60 | { | 152 | { |
| 61 | int i; | 153 | int i; |
| 62 | 154 | ||
| 155 | s6_gmac_resource[5].start = prepare_phy_irq(GPIO_PHY_IRQ); | ||
| 156 | |||
| 63 | for (i = 0; i < ARRAY_SIZE(platform_devices); i++) | 157 | for (i = 0; i < ARRAY_SIZE(platform_devices); i++) |
| 64 | platform_device_register(&platform_devices[i]); | 158 | platform_device_register(&platform_devices[i]); |
| 65 | return 0; | 159 | return 0; |
diff --git a/arch/xtensa/platforms/s6105/setup.c b/arch/xtensa/platforms/s6105/setup.c index 855ddeadc43d..86ce730f7913 100644 --- a/arch/xtensa/platforms/s6105/setup.c +++ b/arch/xtensa/platforms/s6105/setup.c | |||
| @@ -35,12 +35,21 @@ void __init platform_setup(char **cmdline) | |||
| 35 | { | 35 | { |
| 36 | unsigned long reg; | 36 | unsigned long reg; |
| 37 | 37 | ||
| 38 | reg = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL); | ||
| 39 | reg &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC | | ||
| 40 | S6_GREG1_PLLSEL_GMII_MASK << S6_GREG1_PLLSEL_GMII); | ||
| 41 | reg |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC | | ||
| 42 | S6_GREG1_PLLSEL_GMII_125MHZ << S6_GREG1_PLLSEL_GMII; | ||
| 43 | writel(reg, S6_REG_GREG1 + S6_GREG1_PLLSEL); | ||
| 44 | |||
| 38 | reg = readl(S6_REG_GREG1 + S6_GREG1_CLKGATE); | 45 | reg = readl(S6_REG_GREG1 + S6_GREG1_CLKGATE); |
| 39 | reg &= ~(1 << S6_GREG1_BLOCK_SB); | 46 | reg &= ~(1 << S6_GREG1_BLOCK_SB); |
| 47 | reg &= ~(1 << S6_GREG1_BLOCK_GMAC); | ||
| 40 | writel(reg, S6_REG_GREG1 + S6_GREG1_CLKGATE); | 48 | writel(reg, S6_REG_GREG1 + S6_GREG1_CLKGATE); |
| 41 | 49 | ||
| 42 | reg = readl(S6_REG_GREG1 + S6_GREG1_BLOCKENA); | 50 | reg = readl(S6_REG_GREG1 + S6_GREG1_BLOCKENA); |
| 43 | reg |= 1 << S6_GREG1_BLOCK_SB; | 51 | reg |= 1 << S6_GREG1_BLOCK_SB; |
| 52 | reg |= 1 << S6_GREG1_BLOCK_GMAC; | ||
| 44 | writel(reg, S6_REG_GREG1 + S6_GREG1_BLOCKENA); | 53 | writel(reg, S6_REG_GREG1 + S6_GREG1_BLOCKENA); |
| 45 | 54 | ||
| 46 | printk(KERN_NOTICE "S6105 on Stretch S6000 - " | 55 | printk(KERN_NOTICE "S6105 on Stretch S6000 - " |
| @@ -49,7 +58,7 @@ void __init platform_setup(char **cmdline) | |||
| 49 | 58 | ||
| 50 | void __init platform_init(bp_tag_t *first) | 59 | void __init platform_init(bp_tag_t *first) |
| 51 | { | 60 | { |
| 52 | s6_gpio_init(); | 61 | s6_gpio_init(0); |
| 53 | gpio_request(GPIO_LED1_NGREEN, "led1_green"); | 62 | gpio_request(GPIO_LED1_NGREEN, "led1_green"); |
| 54 | gpio_request(GPIO_LED1_RED, "led1_red"); | 63 | gpio_request(GPIO_LED1_RED, "led1_red"); |
| 55 | gpio_direction_output(GPIO_LED1_NGREEN, 1); | 64 | gpio_direction_output(GPIO_LED1_NGREEN, 1); |
diff --git a/arch/xtensa/variants/s6000/Makefile b/arch/xtensa/variants/s6000/Makefile index d83f3805130c..3e7ef0a0c498 100644 --- a/arch/xtensa/variants/s6000/Makefile +++ b/arch/xtensa/variants/s6000/Makefile | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | # s6000 Makefile | 1 | # s6000 Makefile |
| 2 | 2 | ||
| 3 | obj-y += irq.o gpio.o | 3 | obj-y += irq.o gpio.o dmac.o |
| 4 | obj-$(CONFIG_XTENSA_CALIBRATE_CCOUNT) += delay.o | 4 | obj-$(CONFIG_XTENSA_CALIBRATE_CCOUNT) += delay.o |
diff --git a/arch/xtensa/variants/s6000/dmac.c b/arch/xtensa/variants/s6000/dmac.c new file mode 100644 index 000000000000..dc7f7c573518 --- /dev/null +++ b/arch/xtensa/variants/s6000/dmac.c | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | /* | ||
| 2 | * Authors: Oskar Schirmer <os@emlix.com> | ||
| 3 | * Daniel Gloeckner <dg@emlix.com> | ||
| 4 | * (c) 2008 emlix GmbH http://www.emlix.com | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License as published by the | ||
| 8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 9 | * option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/io.h> | ||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/errno.h> | ||
| 16 | #include <linux/spinlock.h> | ||
| 17 | #include <asm/cacheflush.h> | ||
| 18 | #include <variant/dmac.h> | ||
| 19 | |||
| 20 | /* DMA engine lookup */ | ||
| 21 | |||
| 22 | struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB]; | ||
| 23 | |||
| 24 | |||
| 25 | /* DMA control, per engine */ | ||
| 26 | |||
| 27 | void s6dmac_put_fifo_cache(u32 dmac, int chan, u32 src, u32 dst, u32 size) | ||
| 28 | { | ||
| 29 | if (xtensa_need_flush_dma_source(src)) { | ||
| 30 | u32 base = src; | ||
| 31 | u32 span = size; | ||
| 32 | u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK); | ||
| 33 | if (chunk && (size > chunk)) { | ||
| 34 | s32 skip = | ||
| 35 | readl(DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP); | ||
| 36 | u32 gaps = (size+chunk-1)/chunk - 1; | ||
| 37 | if (skip >= 0) { | ||
| 38 | span += gaps * skip; | ||
| 39 | } else if (-skip > chunk) { | ||
| 40 | s32 decr = gaps * (chunk + skip); | ||
| 41 | base += decr; | ||
| 42 | span = chunk - decr; | ||
| 43 | } else { | ||
| 44 | span = max(span + gaps * skip, | ||
| 45 | (chunk + skip) * gaps - skip); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | flush_dcache_unaligned(base, span); | ||
| 49 | } | ||
| 50 | if (xtensa_need_invalidate_dma_destination(dst)) { | ||
| 51 | u32 base = dst; | ||
| 52 | u32 span = size; | ||
| 53 | u32 chunk = readl(DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK); | ||
| 54 | if (chunk && (size > chunk)) { | ||
| 55 | s32 skip = | ||
| 56 | readl(DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP); | ||
| 57 | u32 gaps = (size+chunk-1)/chunk - 1; | ||
| 58 | if (skip >= 0) { | ||
| 59 | span += gaps * skip; | ||
| 60 | } else if (-skip > chunk) { | ||
| 61 | s32 decr = gaps * (chunk + skip); | ||
| 62 | base += decr; | ||
| 63 | span = chunk - decr; | ||
| 64 | } else { | ||
| 65 | span = max(span + gaps * skip, | ||
| 66 | (chunk + skip) * gaps - skip); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | invalidate_dcache_unaligned(base, span); | ||
| 70 | } | ||
| 71 | s6dmac_put_fifo(dmac, chan, src, dst, size); | ||
| 72 | } | ||
| 73 | |||
| 74 | void s6dmac_disable_error_irqs(u32 dmac, u32 mask) | ||
| 75 | { | ||
| 76 | unsigned long flags; | ||
| 77 | spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock; | ||
| 78 | spin_lock_irqsave(spinl, flags); | ||
| 79 | _s6dmac_disable_error_irqs(dmac, mask); | ||
| 80 | spin_unlock_irqrestore(spinl, flags); | ||
| 81 | } | ||
| 82 | |||
| 83 | u32 s6dmac_int_sources(u32 dmac, u32 channel) | ||
| 84 | { | ||
| 85 | u32 mask, ret, tmp; | ||
| 86 | mask = 1 << channel; | ||
| 87 | |||
| 88 | tmp = readl(dmac + S6_DMA_TERMCNTIRQSTAT); | ||
| 89 | tmp &= mask; | ||
| 90 | writel(tmp, dmac + S6_DMA_TERMCNTIRQCLR); | ||
| 91 | ret = tmp >> channel; | ||
| 92 | |||
| 93 | tmp = readl(dmac + S6_DMA_PENDCNTIRQSTAT); | ||
| 94 | tmp &= mask; | ||
| 95 | writel(tmp, dmac + S6_DMA_PENDCNTIRQCLR); | ||
| 96 | ret |= (tmp >> channel) << 1; | ||
| 97 | |||
| 98 | tmp = readl(dmac + S6_DMA_LOWWMRKIRQSTAT); | ||
| 99 | tmp &= mask; | ||
| 100 | writel(tmp, dmac + S6_DMA_LOWWMRKIRQCLR); | ||
| 101 | ret |= (tmp >> channel) << 2; | ||
| 102 | |||
| 103 | tmp = readl(dmac + S6_DMA_INTRAW0); | ||
| 104 | tmp &= (mask << S6_DMA_INT0_OVER) | (mask << S6_DMA_INT0_UNDER); | ||
| 105 | writel(tmp, dmac + S6_DMA_INTCLEAR0); | ||
| 106 | |||
| 107 | if (tmp & (mask << S6_DMA_INT0_UNDER)) | ||
| 108 | ret |= 1 << 3; | ||
| 109 | if (tmp & (mask << S6_DMA_INT0_OVER)) | ||
| 110 | ret |= 1 << 4; | ||
| 111 | |||
| 112 | tmp = readl(dmac + S6_DMA_MASTERERRINFO); | ||
| 113 | mask <<= S6_DMA_INT1_CHANNEL; | ||
| 114 | if (((tmp >> S6_DMA_MASTERERR_CHAN(0)) & S6_DMA_MASTERERR_CHAN_MASK) | ||
| 115 | == channel) | ||
| 116 | mask |= 1 << S6_DMA_INT1_MASTER; | ||
| 117 | if (((tmp >> S6_DMA_MASTERERR_CHAN(1)) & S6_DMA_MASTERERR_CHAN_MASK) | ||
| 118 | == channel) | ||
| 119 | mask |= 1 << (S6_DMA_INT1_MASTER + 1); | ||
| 120 | if (((tmp >> S6_DMA_MASTERERR_CHAN(2)) & S6_DMA_MASTERERR_CHAN_MASK) | ||
| 121 | == channel) | ||
| 122 | mask |= 1 << (S6_DMA_INT1_MASTER + 2); | ||
| 123 | |||
| 124 | tmp = readl(dmac + S6_DMA_INTRAW1) & mask; | ||
| 125 | writel(tmp, dmac + S6_DMA_INTCLEAR1); | ||
| 126 | ret |= ((tmp >> channel) & 1) << 5; | ||
| 127 | ret |= ((tmp >> S6_DMA_INT1_MASTER) & S6_DMA_INT1_MASTER_MASK) << 6; | ||
| 128 | |||
| 129 | return ret; | ||
| 130 | } | ||
| 131 | |||
| 132 | void s6dmac_release_chan(u32 dmac, int chan) | ||
| 133 | { | ||
| 134 | if (chan >= 0) | ||
| 135 | s6dmac_disable_chan(dmac, chan); | ||
| 136 | } | ||
| 137 | |||
| 138 | |||
| 139 | /* global init */ | ||
| 140 | |||
| 141 | static inline void __init dmac_init(u32 dmac, u8 chan_nb) | ||
| 142 | { | ||
| 143 | s6dmac_ctrl[S6_DMAC_INDEX(dmac)].dmac = dmac; | ||
| 144 | spin_lock_init(&s6dmac_ctrl[S6_DMAC_INDEX(dmac)].lock); | ||
| 145 | s6dmac_ctrl[S6_DMAC_INDEX(dmac)].chan_nb = chan_nb; | ||
| 146 | writel(S6_DMA_INT1_MASTER_MASK << S6_DMA_INT1_MASTER, | ||
| 147 | dmac + S6_DMA_INTCLEAR1); | ||
| 148 | } | ||
| 149 | |||
| 150 | static inline void __init dmac_master(u32 dmac, | ||
| 151 | u32 m0start, u32 m0end, u32 m1start, u32 m1end) | ||
| 152 | { | ||
| 153 | writel(m0start, dmac + S6_DMA_MASTER0START); | ||
| 154 | writel(m0end - 1, dmac + S6_DMA_MASTER0END); | ||
| 155 | writel(m1start, dmac + S6_DMA_MASTER1START); | ||
| 156 | writel(m1end - 1, dmac + S6_DMA_MASTER1END); | ||
| 157 | } | ||
| 158 | |||
| 159 | static void __init s6_dmac_init(void) | ||
| 160 | { | ||
| 161 | dmac_init(S6_REG_LMSDMA, S6_LMSDMA_NB); | ||
| 162 | dmac_master(S6_REG_LMSDMA, | ||
| 163 | S6_MEM_DDR, S6_MEM_PCIE_APER, S6_MEM_EFI, S6_MEM_GMAC); | ||
| 164 | dmac_init(S6_REG_NIDMA, S6_NIDMA_NB); | ||
| 165 | dmac_init(S6_REG_DPDMA, S6_DPDMA_NB); | ||
| 166 | dmac_master(S6_REG_DPDMA, | ||
| 167 | S6_MEM_DDR, S6_MEM_PCIE_APER, S6_REG_DP, S6_REG_DPDMA); | ||
| 168 | dmac_init(S6_REG_HIFDMA, S6_HIFDMA_NB); | ||
| 169 | dmac_master(S6_REG_HIFDMA, | ||
| 170 | S6_MEM_GMAC, S6_MEM_PCIE_CFG, S6_MEM_PCIE_APER, S6_MEM_AUX); | ||
| 171 | } | ||
| 172 | |||
| 173 | arch_initcall(s6_dmac_init); | ||
diff --git a/arch/xtensa/variants/s6000/gpio.c b/arch/xtensa/variants/s6000/gpio.c index 79317fdcf14c..380a70fff756 100644 --- a/arch/xtensa/variants/s6000/gpio.c +++ b/arch/xtensa/variants/s6000/gpio.c | |||
| @@ -4,15 +4,20 @@ | |||
| 4 | * Copyright (c) 2009 emlix GmbH | 4 | * Copyright (c) 2009 emlix GmbH |
| 5 | * Authors: Oskar Schirmer <os@emlix.com> | 5 | * Authors: Oskar Schirmer <os@emlix.com> |
| 6 | * Johannes Weiner <jw@emlix.com> | 6 | * Johannes Weiner <jw@emlix.com> |
| 7 | * Daniel Gloeckner <dg@emlix.com> | ||
| 7 | */ | 8 | */ |
| 9 | #include <linux/bitops.h> | ||
| 8 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 9 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 10 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 11 | #include <linux/io.h> | 13 | #include <linux/io.h> |
| 14 | #include <linux/irq.h> | ||
| 12 | #include <linux/gpio.h> | 15 | #include <linux/gpio.h> |
| 13 | 16 | ||
| 14 | #include <variant/hardware.h> | 17 | #include <variant/hardware.h> |
| 15 | 18 | ||
| 19 | #define IRQ_BASE XTENSA_NR_IRQS | ||
| 20 | |||
| 16 | #define S6_GPIO_DATA 0x000 | 21 | #define S6_GPIO_DATA 0x000 |
| 17 | #define S6_GPIO_IS 0x404 | 22 | #define S6_GPIO_IS 0x404 |
| 18 | #define S6_GPIO_IBE 0x408 | 23 | #define S6_GPIO_IBE 0x408 |
| @@ -52,19 +57,175 @@ static void set(struct gpio_chip *chip, unsigned int off, int val) | |||
| 52 | writeb(val ? ~0 : 0, S6_REG_GPIO + S6_GPIO_DATA + S6_GPIO_OFFSET(off)); | 57 | writeb(val ? ~0 : 0, S6_REG_GPIO + S6_GPIO_DATA + S6_GPIO_OFFSET(off)); |
| 53 | } | 58 | } |
| 54 | 59 | ||
| 60 | static int to_irq(struct gpio_chip *chip, unsigned offset) | ||
| 61 | { | ||
| 62 | if (offset < 8) | ||
| 63 | return offset + IRQ_BASE; | ||
| 64 | return -EINVAL; | ||
| 65 | } | ||
| 66 | |||
| 55 | static struct gpio_chip gpiochip = { | 67 | static struct gpio_chip gpiochip = { |
| 56 | .owner = THIS_MODULE, | 68 | .owner = THIS_MODULE, |
| 57 | .direction_input = direction_input, | 69 | .direction_input = direction_input, |
| 58 | .get = get, | 70 | .get = get, |
| 59 | .direction_output = direction_output, | 71 | .direction_output = direction_output, |
| 60 | .set = set, | 72 | .set = set, |
| 73 | .to_irq = to_irq, | ||
| 61 | .base = 0, | 74 | .base = 0, |
| 62 | .ngpio = 24, | 75 | .ngpio = 24, |
| 63 | .can_sleep = 0, /* no blocking io needed */ | 76 | .can_sleep = 0, /* no blocking io needed */ |
| 64 | .exported = 0, /* no exporting to userspace */ | 77 | .exported = 0, /* no exporting to userspace */ |
| 65 | }; | 78 | }; |
| 66 | 79 | ||
| 67 | int s6_gpio_init(void) | 80 | int s6_gpio_init(u32 afsel) |
| 68 | { | 81 | { |
| 82 | writeb(afsel, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_AFSEL); | ||
| 83 | writeb(afsel >> 8, S6_REG_GPIO + S6_GPIO_BANK(1) + S6_GPIO_AFSEL); | ||
| 84 | writeb(afsel >> 16, S6_REG_GPIO + S6_GPIO_BANK(2) + S6_GPIO_AFSEL); | ||
| 69 | return gpiochip_add(&gpiochip); | 85 | return gpiochip_add(&gpiochip); |
| 70 | } | 86 | } |
| 87 | |||
| 88 | static void ack(unsigned int irq) | ||
| 89 | { | ||
| 90 | writeb(1 << (irq - IRQ_BASE), S6_REG_GPIO + S6_GPIO_IC); | ||
| 91 | } | ||
| 92 | |||
| 93 | static void mask(unsigned int irq) | ||
| 94 | { | ||
| 95 | u8 r = readb(S6_REG_GPIO + S6_GPIO_IE); | ||
| 96 | r &= ~(1 << (irq - IRQ_BASE)); | ||
| 97 | writeb(r, S6_REG_GPIO + S6_GPIO_IE); | ||
| 98 | } | ||
| 99 | |||
| 100 | static void unmask(unsigned int irq) | ||
| 101 | { | ||
| 102 | u8 m = readb(S6_REG_GPIO + S6_GPIO_IE); | ||
| 103 | m |= 1 << (irq - IRQ_BASE); | ||
| 104 | writeb(m, S6_REG_GPIO + S6_GPIO_IE); | ||
| 105 | } | ||
| 106 | |||
| 107 | static int set_type(unsigned int irq, unsigned int type) | ||
| 108 | { | ||
| 109 | const u8 m = 1 << (irq - IRQ_BASE); | ||
| 110 | irq_flow_handler_t handler; | ||
| 111 | struct irq_desc *desc; | ||
| 112 | u8 reg; | ||
| 113 | |||
| 114 | if (type == IRQ_TYPE_PROBE) { | ||
| 115 | if ((readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_AFSEL) & m) | ||
| 116 | || (readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IE) & m) | ||
| 117 | || readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_DIR | ||
| 118 | + S6_GPIO_MASK(irq - IRQ_BASE))) | ||
| 119 | return 0; | ||
| 120 | type = IRQ_TYPE_EDGE_BOTH; | ||
| 121 | } | ||
| 122 | |||
| 123 | reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS); | ||
| 124 | if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { | ||
| 125 | reg |= m; | ||
| 126 | handler = handle_level_irq; | ||
| 127 | } else { | ||
| 128 | reg &= ~m; | ||
| 129 | handler = handle_edge_irq; | ||
| 130 | } | ||
| 131 | writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IS); | ||
| 132 | desc = irq_to_desc(irq); | ||
| 133 | desc->handle_irq = handler; | ||
| 134 | |||
| 135 | reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV); | ||
| 136 | if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)) | ||
| 137 | reg |= m; | ||
| 138 | else | ||
| 139 | reg &= ~m; | ||
| 140 | writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IEV); | ||
| 141 | |||
| 142 | reg = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IBE); | ||
| 143 | if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) | ||
| 144 | reg |= m; | ||
| 145 | else | ||
| 146 | reg &= ~m; | ||
| 147 | writeb(reg, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IBE); | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static struct irq_chip gpioirqs = { | ||
| 152 | .name = "GPIO", | ||
| 153 | .ack = ack, | ||
| 154 | .mask = mask, | ||
| 155 | .unmask = unmask, | ||
| 156 | .set_type = set_type, | ||
| 157 | }; | ||
| 158 | |||
| 159 | static u8 demux_masks[4]; | ||
| 160 | |||
| 161 | static void demux_irqs(unsigned int irq, struct irq_desc *desc) | ||
| 162 | { | ||
| 163 | u8 *mask = get_irq_desc_data(desc); | ||
| 164 | u8 pending; | ||
| 165 | int cirq; | ||
| 166 | |||
| 167 | desc->chip->mask(irq); | ||
| 168 | desc->chip->ack(irq); | ||
| 169 | pending = readb(S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_MIS) & *mask; | ||
| 170 | cirq = IRQ_BASE - 1; | ||
| 171 | while (pending) { | ||
| 172 | int n = ffs(pending); | ||
| 173 | cirq += n; | ||
| 174 | pending >>= n; | ||
| 175 | generic_handle_irq(cirq); | ||
| 176 | } | ||
| 177 | desc->chip->unmask(irq); | ||
| 178 | } | ||
| 179 | |||
| 180 | extern const signed char *platform_irq_mappings[XTENSA_NR_IRQS]; | ||
| 181 | |||
| 182 | void __init variant_init_irq(void) | ||
| 183 | { | ||
| 184 | int irq, n; | ||
| 185 | writeb(0, S6_REG_GPIO + S6_GPIO_BANK(0) + S6_GPIO_IE); | ||
| 186 | for (irq = n = 0; irq < XTENSA_NR_IRQS; irq++) { | ||
| 187 | const signed char *mapping = platform_irq_mappings[irq]; | ||
| 188 | int alone = 1; | ||
| 189 | u8 mask; | ||
| 190 | if (!mapping) | ||
| 191 | continue; | ||
| 192 | for(mask = 0; *mapping != -1; mapping++) | ||
| 193 | switch (*mapping) { | ||
| 194 | case S6_INTC_GPIO(0): | ||
| 195 | mask |= 1 << 0; | ||
| 196 | break; | ||
| 197 | case S6_INTC_GPIO(1): | ||
| 198 | mask |= 1 << 1; | ||
| 199 | break; | ||
| 200 | case S6_INTC_GPIO(2): | ||
| 201 | mask |= 1 << 2; | ||
| 202 | break; | ||
| 203 | case S6_INTC_GPIO(3): | ||
| 204 | mask |= 0x1f << 3; | ||
| 205 | break; | ||
| 206 | default: | ||
| 207 | alone = 0; | ||
| 208 | } | ||
| 209 | if (mask) { | ||
| 210 | int cirq, i; | ||
| 211 | if (!alone) { | ||
| 212 | printk(KERN_ERR "chained irq chips can't share" | ||
| 213 | " parent irq %i\n", irq); | ||
| 214 | continue; | ||
| 215 | } | ||
| 216 | demux_masks[n] = mask; | ||
| 217 | cirq = IRQ_BASE - 1; | ||
| 218 | do { | ||
| 219 | i = ffs(mask); | ||
| 220 | cirq += i; | ||
| 221 | mask >>= i; | ||
| 222 | set_irq_chip(cirq, &gpioirqs); | ||
| 223 | set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); | ||
| 224 | } while (mask); | ||
| 225 | set_irq_data(irq, demux_masks + n); | ||
| 226 | set_irq_chained_handler(irq, demux_irqs); | ||
| 227 | if (++n == ARRAY_SIZE(demux_masks)) | ||
| 228 | break; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | } | ||
diff --git a/arch/xtensa/variants/s6000/include/variant/dmac.h b/arch/xtensa/variants/s6000/include/variant/dmac.h new file mode 100644 index 000000000000..89ab9484fb71 --- /dev/null +++ b/arch/xtensa/variants/s6000/include/variant/dmac.h | |||
| @@ -0,0 +1,387 @@ | |||
| 1 | /* | ||
| 2 | * include/asm-xtensa/variant-s6000/dmac.h | ||
| 3 | * | ||
| 4 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 5 | * License. See the file "COPYING" in the main directory of this archive | ||
| 6 | * for more details. | ||
| 7 | * | ||
| 8 | * Copyright (C) 2006 Tensilica Inc. | ||
| 9 | * Copyright (C) 2008 Emlix GmbH <info@emlix.com> | ||
| 10 | * Authors: Fabian Godehardt <fg@emlix.com> | ||
| 11 | * Oskar Schirmer <os@emlix.com> | ||
| 12 | * Daniel Gloeckner <dg@emlix.com> | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __ASM_XTENSA_S6000_DMAC_H | ||
| 16 | #define __ASM_XTENSA_S6000_DMAC_H | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <variant/hardware.h> | ||
| 19 | |||
| 20 | /* DMA global */ | ||
| 21 | |||
| 22 | #define S6_DMA_INTSTAT0 0x000 | ||
| 23 | #define S6_DMA_INTSTAT1 0x004 | ||
| 24 | #define S6_DMA_INTENABLE0 0x008 | ||
| 25 | #define S6_DMA_INTENABLE1 0x00C | ||
| 26 | #define S6_DMA_INTRAW0 0x010 | ||
| 27 | #define S6_DMA_INTRAW1 0x014 | ||
| 28 | #define S6_DMA_INTCLEAR0 0x018 | ||
| 29 | #define S6_DMA_INTCLEAR1 0x01C | ||
| 30 | #define S6_DMA_INTSET0 0x020 | ||
| 31 | #define S6_DMA_INTSET1 0x024 | ||
| 32 | #define S6_DMA_INT0_UNDER 0 | ||
| 33 | #define S6_DMA_INT0_OVER 16 | ||
| 34 | #define S6_DMA_INT1_CHANNEL 0 | ||
| 35 | #define S6_DMA_INT1_MASTER 16 | ||
| 36 | #define S6_DMA_INT1_MASTER_MASK 7 | ||
| 37 | #define S6_DMA_TERMCNTIRQSTAT 0x028 | ||
| 38 | #define S6_DMA_TERMCNTIRQCLR 0x02C | ||
| 39 | #define S6_DMA_TERMCNTIRQSET 0x030 | ||
| 40 | #define S6_DMA_PENDCNTIRQSTAT 0x034 | ||
| 41 | #define S6_DMA_PENDCNTIRQCLR 0x038 | ||
| 42 | #define S6_DMA_PENDCNTIRQSET 0x03C | ||
| 43 | #define S6_DMA_LOWWMRKIRQSTAT 0x040 | ||
| 44 | #define S6_DMA_LOWWMRKIRQCLR 0x044 | ||
| 45 | #define S6_DMA_LOWWMRKIRQSET 0x048 | ||
| 46 | #define S6_DMA_MASTERERRINFO 0x04C | ||
| 47 | #define S6_DMA_MASTERERR_CHAN(n) (4*(n)) | ||
| 48 | #define S6_DMA_MASTERERR_CHAN_MASK 0xF | ||
| 49 | #define S6_DMA_DESCRFIFO0 0x050 | ||
| 50 | #define S6_DMA_DESCRFIFO1 0x054 | ||
| 51 | #define S6_DMA_DESCRFIFO2 0x058 | ||
| 52 | #define S6_DMA_DESCRFIFO2_AUTODISABLE 24 | ||
| 53 | #define S6_DMA_DESCRFIFO3 0x05C | ||
| 54 | #define S6_DMA_MASTER0START 0x060 | ||
| 55 | #define S6_DMA_MASTER0END 0x064 | ||
| 56 | #define S6_DMA_MASTER1START 0x068 | ||
| 57 | #define S6_DMA_MASTER1END 0x06C | ||
| 58 | #define S6_DMA_NEXTFREE 0x070 | ||
| 59 | #define S6_DMA_NEXTFREE_CHAN 0 | ||
| 60 | #define S6_DMA_NEXTFREE_CHAN_MASK 0x1F | ||
| 61 | #define S6_DMA_NEXTFREE_ENA 16 | ||
| 62 | #define S6_DMA_NEXTFREE_ENA_MASK ((1 << 16) - 1) | ||
| 63 | #define S6_DMA_DPORTCTRLGRP(p) ((p) * 4 + 0x074) | ||
| 64 | #define S6_DMA_DPORTCTRLGRP_FRAMEREP 0 | ||
| 65 | #define S6_DMA_DPORTCTRLGRP_NRCHANS 1 | ||
| 66 | #define S6_DMA_DPORTCTRLGRP_NRCHANS_1 0 | ||
| 67 | #define S6_DMA_DPORTCTRLGRP_NRCHANS_3 1 | ||
| 68 | #define S6_DMA_DPORTCTRLGRP_NRCHANS_4 2 | ||
| 69 | #define S6_DMA_DPORTCTRLGRP_NRCHANS_2 3 | ||
| 70 | #define S6_DMA_DPORTCTRLGRP_ENA 31 | ||
| 71 | |||
| 72 | |||
| 73 | /* DMA per channel */ | ||
| 74 | |||
| 75 | #define DMA_CHNL(dmac, n) ((dmac) + 0x1000 + (n) * 0x100) | ||
| 76 | #define DMA_INDEX_CHNL(addr) (((addr) >> 8) & 0xF) | ||
| 77 | #define DMA_MASK_DMAC(addr) ((addr) & 0xFFFF0000) | ||
| 78 | #define S6_DMA_CHNCTRL 0x000 | ||
| 79 | #define S6_DMA_CHNCTRL_ENABLE 0 | ||
| 80 | #define S6_DMA_CHNCTRL_PAUSE 1 | ||
| 81 | #define S6_DMA_CHNCTRL_PRIO 2 | ||
| 82 | #define S6_DMA_CHNCTRL_PRIO_MASK 3 | ||
| 83 | #define S6_DMA_CHNCTRL_PERIPHXFER 4 | ||
| 84 | #define S6_DMA_CHNCTRL_PERIPHENA 5 | ||
| 85 | #define S6_DMA_CHNCTRL_SRCINC 6 | ||
| 86 | #define S6_DMA_CHNCTRL_DSTINC 7 | ||
| 87 | #define S6_DMA_CHNCTRL_BURSTLOG 8 | ||
| 88 | #define S6_DMA_CHNCTRL_BURSTLOG_MASK 7 | ||
| 89 | #define S6_DMA_CHNCTRL_DESCFIFODEPTH 12 | ||
| 90 | #define S6_DMA_CHNCTRL_DESCFIFODEPTH_MASK 0x1F | ||
| 91 | #define S6_DMA_CHNCTRL_DESCFIFOFULL 17 | ||
| 92 | #define S6_DMA_CHNCTRL_BWCONSEL 18 | ||
| 93 | #define S6_DMA_CHNCTRL_BWCONENA 19 | ||
| 94 | #define S6_DMA_CHNCTRL_PENDGCNTSTAT 20 | ||
| 95 | #define S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK 0x3F | ||
| 96 | #define S6_DMA_CHNCTRL_LOWWMARK 26 | ||
| 97 | #define S6_DMA_CHNCTRL_LOWWMARK_MASK 0xF | ||
| 98 | #define S6_DMA_CHNCTRL_TSTAMP 30 | ||
| 99 | #define S6_DMA_TERMCNTNB 0x004 | ||
| 100 | #define S6_DMA_TERMCNTNB_MASK 0xFFFF | ||
| 101 | #define S6_DMA_TERMCNTTMO 0x008 | ||
| 102 | #define S6_DMA_TERMCNTSTAT 0x00C | ||
| 103 | #define S6_DMA_TERMCNTSTAT_MASK 0xFF | ||
| 104 | #define S6_DMA_CMONCHUNK 0x010 | ||
| 105 | #define S6_DMA_SRCSKIP 0x014 | ||
| 106 | #define S6_DMA_DSTSKIP 0x018 | ||
| 107 | #define S6_DMA_CUR_SRC 0x024 | ||
| 108 | #define S6_DMA_CUR_DST 0x028 | ||
| 109 | #define S6_DMA_TIMESTAMP 0x030 | ||
| 110 | |||
| 111 | /* DMA channel lists */ | ||
| 112 | |||
| 113 | #define S6_DPDMA_CHAN(stream, channel) (4 * (stream) + (channel)) | ||
| 114 | #define S6_DPDMA_NB 16 | ||
| 115 | |||
| 116 | #define S6_HIFDMA_GMACTX 0 | ||
| 117 | #define S6_HIFDMA_GMACRX 1 | ||
| 118 | #define S6_HIFDMA_I2S0 2 | ||
| 119 | #define S6_HIFDMA_I2S1 3 | ||
| 120 | #define S6_HIFDMA_EGIB 4 | ||
| 121 | #define S6_HIFDMA_PCITX 5 | ||
| 122 | #define S6_HIFDMA_PCIRX 6 | ||
| 123 | #define S6_HIFDMA_NB 7 | ||
| 124 | |||
| 125 | #define S6_NIDMA_NB 4 | ||
| 126 | |||
| 127 | #define S6_LMSDMA_NB 12 | ||
| 128 | |||
| 129 | /* controller access */ | ||
| 130 | |||
| 131 | #define S6_DMAC_NB 4 | ||
| 132 | #define S6_DMAC_INDEX(dmac) (((unsigned)(dmac) >> 18) % S6_DMAC_NB) | ||
| 133 | |||
| 134 | struct s6dmac_ctrl { | ||
| 135 | u32 dmac; | ||
| 136 | spinlock_t lock; | ||
| 137 | u8 chan_nb; | ||
| 138 | }; | ||
| 139 | |||
| 140 | extern struct s6dmac_ctrl s6dmac_ctrl[S6_DMAC_NB]; | ||
| 141 | |||
| 142 | |||
| 143 | /* DMA control, per channel */ | ||
| 144 | |||
| 145 | static inline int s6dmac_fifo_full(u32 dmac, int chan) | ||
| 146 | { | ||
| 147 | return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) | ||
| 148 | & (1 << S6_DMA_CHNCTRL_DESCFIFOFULL)) && 1; | ||
| 149 | } | ||
| 150 | |||
| 151 | static inline int s6dmac_termcnt_irq(u32 dmac, int chan) | ||
| 152 | { | ||
| 153 | u32 m = 1 << chan; | ||
| 154 | int r = (readl(dmac + S6_DMA_TERMCNTIRQSTAT) & m) && 1; | ||
| 155 | if (r) | ||
| 156 | writel(m, dmac + S6_DMA_TERMCNTIRQCLR); | ||
| 157 | return r; | ||
| 158 | } | ||
| 159 | |||
| 160 | static inline int s6dmac_pendcnt_irq(u32 dmac, int chan) | ||
| 161 | { | ||
| 162 | u32 m = 1 << chan; | ||
| 163 | int r = (readl(dmac + S6_DMA_PENDCNTIRQSTAT) & m) && 1; | ||
| 164 | if (r) | ||
| 165 | writel(m, dmac + S6_DMA_PENDCNTIRQCLR); | ||
| 166 | return r; | ||
| 167 | } | ||
| 168 | |||
| 169 | static inline int s6dmac_lowwmark_irq(u32 dmac, int chan) | ||
| 170 | { | ||
| 171 | int r = (readl(dmac + S6_DMA_LOWWMRKIRQSTAT) & (1 << chan)) ? 1 : 0; | ||
| 172 | if (r) | ||
| 173 | writel(1 << chan, dmac + S6_DMA_LOWWMRKIRQCLR); | ||
| 174 | return r; | ||
| 175 | } | ||
| 176 | |||
| 177 | static inline u32 s6dmac_pending_count(u32 dmac, int chan) | ||
| 178 | { | ||
| 179 | return (readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) | ||
| 180 | >> S6_DMA_CHNCTRL_PENDGCNTSTAT) | ||
| 181 | & S6_DMA_CHNCTRL_PENDGCNTSTAT_MASK; | ||
| 182 | } | ||
| 183 | |||
| 184 | static inline void s6dmac_set_terminal_count(u32 dmac, int chan, u32 n) | ||
| 185 | { | ||
| 186 | n &= S6_DMA_TERMCNTNB_MASK; | ||
| 187 | n |= readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB) | ||
| 188 | & ~S6_DMA_TERMCNTNB_MASK; | ||
| 189 | writel(n, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB); | ||
| 190 | } | ||
| 191 | |||
| 192 | static inline u32 s6dmac_get_terminal_count(u32 dmac, int chan) | ||
| 193 | { | ||
| 194 | return (readl(DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB)) | ||
| 195 | & S6_DMA_TERMCNTNB_MASK; | ||
| 196 | } | ||
| 197 | |||
| 198 | static inline u32 s6dmac_timestamp(u32 dmac, int chan) | ||
| 199 | { | ||
| 200 | return readl(DMA_CHNL(dmac, chan) + S6_DMA_TIMESTAMP); | ||
| 201 | } | ||
| 202 | |||
| 203 | static inline u32 s6dmac_cur_src(u32 dmac, int chan) | ||
| 204 | { | ||
| 205 | return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_SRC); | ||
| 206 | } | ||
| 207 | |||
| 208 | static inline u32 s6dmac_cur_dst(u32 dmac, int chan) | ||
| 209 | { | ||
| 210 | return readl(DMA_CHNL(dmac, chan) + S6_DMA_CUR_DST); | ||
| 211 | } | ||
| 212 | |||
| 213 | static inline void s6dmac_disable_chan(u32 dmac, int chan) | ||
| 214 | { | ||
| 215 | u32 ctrl; | ||
| 216 | writel(readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) | ||
| 217 | & ~(1 << S6_DMA_CHNCTRL_ENABLE), | ||
| 218 | DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); | ||
| 219 | do | ||
| 220 | ctrl = readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); | ||
| 221 | while (ctrl & (1 << S6_DMA_CHNCTRL_ENABLE)); | ||
| 222 | } | ||
| 223 | |||
| 224 | static inline void s6dmac_set_stride_skip(u32 dmac, int chan, | ||
| 225 | int comchunk, /* 0: disable scatter/gather */ | ||
| 226 | int srcskip, int dstskip) | ||
| 227 | { | ||
| 228 | writel(comchunk, DMA_CHNL(dmac, chan) + S6_DMA_CMONCHUNK); | ||
| 229 | writel(srcskip, DMA_CHNL(dmac, chan) + S6_DMA_SRCSKIP); | ||
| 230 | writel(dstskip, DMA_CHNL(dmac, chan) + S6_DMA_DSTSKIP); | ||
| 231 | } | ||
| 232 | |||
| 233 | static inline void s6dmac_enable_chan(u32 dmac, int chan, | ||
| 234 | int prio, /* 0 (highest) .. 3 (lowest) */ | ||
| 235 | int periphxfer, /* <0: disable p.req.line, 0..1: mode */ | ||
| 236 | int srcinc, int dstinc, /* 0: dont increment src/dst address */ | ||
| 237 | int comchunk, /* 0: disable scatter/gather */ | ||
| 238 | int srcskip, int dstskip, | ||
| 239 | int burstsize, /* 4 for I2S, 7 for everything else */ | ||
| 240 | int bandwidthconserve, /* <0: disable, 0..1: select */ | ||
| 241 | int lowwmark, /* 0..15 */ | ||
| 242 | int timestamp, /* 0: disable timestamp */ | ||
| 243 | int enable) /* 0: disable for now */ | ||
| 244 | { | ||
| 245 | writel(1, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTNB); | ||
| 246 | writel(0, DMA_CHNL(dmac, chan) + S6_DMA_TERMCNTTMO); | ||
| 247 | writel(lowwmark << S6_DMA_CHNCTRL_LOWWMARK, | ||
| 248 | DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); | ||
| 249 | s6dmac_set_stride_skip(dmac, chan, comchunk, srcskip, dstskip); | ||
| 250 | writel(((enable ? 1 : 0) << S6_DMA_CHNCTRL_ENABLE) | | ||
| 251 | (prio << S6_DMA_CHNCTRL_PRIO) | | ||
| 252 | (((periphxfer > 0) ? 1 : 0) << S6_DMA_CHNCTRL_PERIPHXFER) | | ||
| 253 | (((periphxfer < 0) ? 0 : 1) << S6_DMA_CHNCTRL_PERIPHENA) | | ||
| 254 | ((srcinc ? 1 : 0) << S6_DMA_CHNCTRL_SRCINC) | | ||
| 255 | ((dstinc ? 1 : 0) << S6_DMA_CHNCTRL_DSTINC) | | ||
| 256 | (burstsize << S6_DMA_CHNCTRL_BURSTLOG) | | ||
| 257 | (((bandwidthconserve > 0) ? 1 : 0) << S6_DMA_CHNCTRL_BWCONSEL) | | ||
| 258 | (((bandwidthconserve < 0) ? 0 : 1) << S6_DMA_CHNCTRL_BWCONENA) | | ||
| 259 | (lowwmark << S6_DMA_CHNCTRL_LOWWMARK) | | ||
| 260 | ((timestamp ? 1 : 0) << S6_DMA_CHNCTRL_TSTAMP), | ||
| 261 | DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL); | ||
| 262 | } | ||
| 263 | |||
| 264 | |||
| 265 | /* DMA control, per engine */ | ||
| 266 | |||
| 267 | static inline unsigned _dmac_addr_index(u32 dmac) | ||
| 268 | { | ||
| 269 | unsigned i = S6_DMAC_INDEX(dmac); | ||
| 270 | if (s6dmac_ctrl[i].dmac != dmac) | ||
| 271 | BUG(); | ||
| 272 | return i; | ||
| 273 | } | ||
| 274 | |||
| 275 | static inline void _s6dmac_disable_error_irqs(u32 dmac, u32 mask) | ||
| 276 | { | ||
| 277 | writel(mask, dmac + S6_DMA_TERMCNTIRQCLR); | ||
| 278 | writel(mask, dmac + S6_DMA_PENDCNTIRQCLR); | ||
| 279 | writel(mask, dmac + S6_DMA_LOWWMRKIRQCLR); | ||
| 280 | writel(readl(dmac + S6_DMA_INTENABLE0) | ||
| 281 | & ~((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER)), | ||
| 282 | dmac + S6_DMA_INTENABLE0); | ||
| 283 | writel(readl(dmac + S6_DMA_INTENABLE1) & ~(mask << S6_DMA_INT1_CHANNEL), | ||
| 284 | dmac + S6_DMA_INTENABLE1); | ||
| 285 | writel((mask << S6_DMA_INT0_UNDER) | (mask << S6_DMA_INT0_OVER), | ||
| 286 | dmac + S6_DMA_INTCLEAR0); | ||
| 287 | writel(mask << S6_DMA_INT1_CHANNEL, dmac + S6_DMA_INTCLEAR1); | ||
| 288 | } | ||
| 289 | |||
| 290 | /* | ||
| 291 | * request channel from specified engine | ||
| 292 | * with chan<0, accept any channel | ||
| 293 | * further parameters see s6dmac_enable_chan | ||
| 294 | * returns < 0 upon error, channel nb otherwise | ||
| 295 | */ | ||
| 296 | static inline int s6dmac_request_chan(u32 dmac, int chan, | ||
| 297 | int prio, | ||
| 298 | int periphxfer, | ||
| 299 | int srcinc, int dstinc, | ||
| 300 | int comchunk, | ||
| 301 | int srcskip, int dstskip, | ||
| 302 | int burstsize, | ||
| 303 | int bandwidthconserve, | ||
| 304 | int lowwmark, | ||
| 305 | int timestamp, | ||
| 306 | int enable) | ||
| 307 | { | ||
| 308 | int r = chan; | ||
| 309 | unsigned long flags; | ||
| 310 | spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock; | ||
| 311 | spin_lock_irqsave(spinl, flags); | ||
| 312 | if (r < 0) { | ||
| 313 | r = (readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_CHAN) | ||
| 314 | & S6_DMA_NEXTFREE_CHAN_MASK; | ||
| 315 | } | ||
| 316 | if (r >= s6dmac_ctrl[_dmac_addr_index(dmac)].chan_nb) { | ||
| 317 | if (chan < 0) | ||
| 318 | r = -EBUSY; | ||
| 319 | else | ||
| 320 | r = -ENXIO; | ||
| 321 | } else if (((readl(dmac + S6_DMA_NEXTFREE) >> S6_DMA_NEXTFREE_ENA) | ||
| 322 | >> r) & 1) { | ||
| 323 | r = -EBUSY; | ||
| 324 | } else { | ||
| 325 | s6dmac_enable_chan(dmac, r, prio, periphxfer, | ||
| 326 | srcinc, dstinc, comchunk, srcskip, dstskip, burstsize, | ||
| 327 | bandwidthconserve, lowwmark, timestamp, enable); | ||
| 328 | } | ||
| 329 | spin_unlock_irqrestore(spinl, flags); | ||
| 330 | return r; | ||
| 331 | } | ||
| 332 | |||
| 333 | static inline void s6dmac_put_fifo(u32 dmac, int chan, | ||
| 334 | u32 src, u32 dst, u32 size) | ||
| 335 | { | ||
| 336 | unsigned long flags; | ||
| 337 | spinlock_t *spinl = &s6dmac_ctrl[_dmac_addr_index(dmac)].lock; | ||
| 338 | spin_lock_irqsave(spinl, flags); | ||
| 339 | writel(src, dmac + S6_DMA_DESCRFIFO0); | ||
| 340 | writel(dst, dmac + S6_DMA_DESCRFIFO1); | ||
| 341 | writel(size, dmac + S6_DMA_DESCRFIFO2); | ||
| 342 | writel(chan, dmac + S6_DMA_DESCRFIFO3); | ||
| 343 | spin_unlock_irqrestore(spinl, flags); | ||
| 344 | } | ||
| 345 | |||
| 346 | static inline u32 s6dmac_channel_enabled(u32 dmac, int chan) | ||
| 347 | { | ||
| 348 | return readl(DMA_CHNL(dmac, chan) + S6_DMA_CHNCTRL) & | ||
| 349 | (1 << S6_DMA_CHNCTRL_ENABLE); | ||
| 350 | } | ||
| 351 | |||
| 352 | /* | ||
| 353 | * group 1-4 data port channels | ||
| 354 | * with port=0..3, nrch=1-4 channels, | ||
| 355 | * frrep=0/1 (dis- or enable frame repeat) | ||
| 356 | */ | ||
| 357 | static inline void s6dmac_dp_setup_group(u32 dmac, int port, | ||
| 358 | int nrch, int frrep) | ||
| 359 | { | ||
| 360 | const static u8 mask[4] = {0, 3, 1, 2}; | ||
| 361 | BUG_ON(dmac != S6_REG_DPDMA); | ||
| 362 | if ((port < 0) || (port > 3) || (nrch < 1) || (nrch > 4)) | ||
| 363 | return; | ||
| 364 | writel((mask[nrch - 1] << S6_DMA_DPORTCTRLGRP_NRCHANS) | ||
| 365 | | ((frrep ? 1 : 0) << S6_DMA_DPORTCTRLGRP_FRAMEREP), | ||
| 366 | dmac + S6_DMA_DPORTCTRLGRP(port)); | ||
| 367 | } | ||
| 368 | |||
| 369 | static inline void s6dmac_dp_switch_group(u32 dmac, int port, int enable) | ||
| 370 | { | ||
| 371 | u32 tmp; | ||
| 372 | BUG_ON(dmac != S6_REG_DPDMA); | ||
| 373 | tmp = readl(dmac + S6_DMA_DPORTCTRLGRP(port)); | ||
| 374 | if (enable) | ||
| 375 | tmp |= (1 << S6_DMA_DPORTCTRLGRP_ENA); | ||
| 376 | else | ||
| 377 | tmp &= ~(1 << S6_DMA_DPORTCTRLGRP_ENA); | ||
| 378 | writel(tmp, dmac + S6_DMA_DPORTCTRLGRP(port)); | ||
| 379 | } | ||
| 380 | |||
| 381 | extern void s6dmac_put_fifo_cache(u32 dmac, int chan, | ||
| 382 | u32 src, u32 dst, u32 size); | ||
| 383 | extern void s6dmac_disable_error_irqs(u32 dmac, u32 mask); | ||
| 384 | extern u32 s6dmac_int_sources(u32 dmac, u32 channel); | ||
| 385 | extern void s6dmac_release_chan(u32 dmac, int chan); | ||
| 386 | |||
| 387 | #endif /* __ASM_XTENSA_S6000_DMAC_H */ | ||
diff --git a/arch/xtensa/variants/s6000/include/variant/gpio.h b/arch/xtensa/variants/s6000/include/variant/gpio.h index 8327f62167eb..8484ab0df461 100644 --- a/arch/xtensa/variants/s6000/include/variant/gpio.h +++ b/arch/xtensa/variants/s6000/include/variant/gpio.h | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #ifndef _XTENSA_VARIANT_S6000_GPIO_H | 1 | #ifndef _XTENSA_VARIANT_S6000_GPIO_H |
| 2 | #define _XTENSA_VARIANT_S6000_GPIO_H | 2 | #define _XTENSA_VARIANT_S6000_GPIO_H |
| 3 | 3 | ||
| 4 | extern int s6_gpio_init(void); | 4 | extern int s6_gpio_init(u32 afsel); |
| 5 | 5 | ||
| 6 | #endif /* _XTENSA_VARIANT_S6000_GPIO_H */ | 6 | #endif /* _XTENSA_VARIANT_S6000_GPIO_H */ |
diff --git a/arch/xtensa/variants/s6000/include/variant/irq.h b/arch/xtensa/variants/s6000/include/variant/irq.h index fa031cb0acc4..97d6fc48deff 100644 --- a/arch/xtensa/variants/s6000/include/variant/irq.h +++ b/arch/xtensa/variants/s6000/include/variant/irq.h | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | #ifndef __XTENSA_S6000_IRQ_H | 1 | #ifndef _XTENSA_S6000_IRQ_H |
| 2 | #define __XTENSA_S6000_IRQ_H | 2 | #define _XTENSA_S6000_IRQ_H |
| 3 | 3 | ||
| 4 | #define NO_IRQ (-1) | 4 | #define NO_IRQ (-1) |
| 5 | #define VARIANT_NR_IRQS 8 /* GPIO interrupts */ | ||
| 5 | 6 | ||
| 6 | extern void variant_irq_enable(unsigned int irq); | 7 | extern void variant_irq_enable(unsigned int irq); |
| 7 | extern void variant_irq_disable(unsigned int irq); | ||
| 8 | 8 | ||
| 9 | #endif /* __XTENSA_S6000_IRQ_H */ | 9 | #endif /* __XTENSA_S6000_IRQ_H */ |
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 892a9e4e275f..1dc721517e4c 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
| @@ -2443,6 +2443,17 @@ config JME | |||
| 2443 | To compile this driver as a module, choose M here. The module | 2443 | To compile this driver as a module, choose M here. The module |
| 2444 | will be called jme. | 2444 | will be called jme. |
| 2445 | 2445 | ||
| 2446 | config S6GMAC | ||
| 2447 | tristate "S6105 GMAC ethernet support" | ||
| 2448 | depends on XTENSA_VARIANT_S6000 | ||
| 2449 | select PHYLIB | ||
| 2450 | help | ||
| 2451 | This driver supports the on chip ethernet device on the | ||
| 2452 | S6105 xtensa processor. | ||
| 2453 | |||
| 2454 | To compile this driver as a module, choose M here. The module | ||
| 2455 | will be called s6gmac. | ||
| 2456 | |||
| 2446 | endif # NETDEV_1000 | 2457 | endif # NETDEV_1000 |
| 2447 | 2458 | ||
| 2448 | # | 2459 | # |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d366fb2b40e9..4b58a59f211b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
| @@ -245,6 +245,7 @@ obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o | |||
| 245 | 245 | ||
| 246 | obj-$(CONFIG_DNET) += dnet.o | 246 | obj-$(CONFIG_DNET) += dnet.o |
| 247 | obj-$(CONFIG_MACB) += macb.o | 247 | obj-$(CONFIG_MACB) += macb.o |
| 248 | obj-$(CONFIG_S6GMAC) += s6gmac.o | ||
| 248 | 249 | ||
| 249 | obj-$(CONFIG_ARM) += arm/ | 250 | obj-$(CONFIG_ARM) += arm/ |
| 250 | obj-$(CONFIG_DEV_APPLETALK) += appletalk/ | 251 | obj-$(CONFIG_DEV_APPLETALK) += appletalk/ |
diff --git a/drivers/net/s6gmac.c b/drivers/net/s6gmac.c new file mode 100644 index 000000000000..5345e47b35ac --- /dev/null +++ b/drivers/net/s6gmac.c | |||
| @@ -0,0 +1,1073 @@ | |||
| 1 | /* | ||
| 2 | * Ethernet driver for S6105 on chip network device | ||
| 3 | * (c)2008 emlix GmbH http://www.emlix.com | ||
| 4 | * Authors: Oskar Schirmer <os@emlix.com> | ||
| 5 | * Daniel Gloeckner <dg@emlix.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; either version | ||
| 10 | * 2 of the License, or (at your option) any later version. | ||
| 11 | */ | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/types.h> | ||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/spinlock.h> | ||
| 19 | #include <linux/netdevice.h> | ||
| 20 | #include <linux/etherdevice.h> | ||
| 21 | #include <linux/if.h> | ||
| 22 | #include <linux/stddef.h> | ||
| 23 | #include <linux/mii.h> | ||
| 24 | #include <linux/phy.h> | ||
| 25 | #include <linux/platform_device.h> | ||
| 26 | #include <variant/hardware.h> | ||
| 27 | #include <variant/dmac.h> | ||
| 28 | |||
| 29 | #define DRV_NAME "s6gmac" | ||
| 30 | #define DRV_PRMT DRV_NAME ": " | ||
| 31 | |||
| 32 | |||
| 33 | /* register declarations */ | ||
| 34 | |||
| 35 | #define S6_GMAC_MACCONF1 0x000 | ||
| 36 | #define S6_GMAC_MACCONF1_TXENA 0 | ||
| 37 | #define S6_GMAC_MACCONF1_SYNCTX 1 | ||
| 38 | #define S6_GMAC_MACCONF1_RXENA 2 | ||
| 39 | #define S6_GMAC_MACCONF1_SYNCRX 3 | ||
| 40 | #define S6_GMAC_MACCONF1_TXFLOWCTRL 4 | ||
| 41 | #define S6_GMAC_MACCONF1_RXFLOWCTRL 5 | ||
| 42 | #define S6_GMAC_MACCONF1_LOOPBACK 8 | ||
| 43 | #define S6_GMAC_MACCONF1_RESTXFUNC 16 | ||
| 44 | #define S6_GMAC_MACCONF1_RESRXFUNC 17 | ||
| 45 | #define S6_GMAC_MACCONF1_RESTXMACCTRL 18 | ||
| 46 | #define S6_GMAC_MACCONF1_RESRXMACCTRL 19 | ||
| 47 | #define S6_GMAC_MACCONF1_SIMULRES 30 | ||
| 48 | #define S6_GMAC_MACCONF1_SOFTRES 31 | ||
| 49 | #define S6_GMAC_MACCONF2 0x004 | ||
| 50 | #define S6_GMAC_MACCONF2_FULL 0 | ||
| 51 | #define S6_GMAC_MACCONF2_CRCENA 1 | ||
| 52 | #define S6_GMAC_MACCONF2_PADCRCENA 2 | ||
| 53 | #define S6_GMAC_MACCONF2_LENGTHFCHK 4 | ||
| 54 | #define S6_GMAC_MACCONF2_HUGEFRAMENA 5 | ||
| 55 | #define S6_GMAC_MACCONF2_IFMODE 8 | ||
| 56 | #define S6_GMAC_MACCONF2_IFMODE_NIBBLE 1 | ||
| 57 | #define S6_GMAC_MACCONF2_IFMODE_BYTE 2 | ||
| 58 | #define S6_GMAC_MACCONF2_IFMODE_MASK 3 | ||
| 59 | #define S6_GMAC_MACCONF2_PREAMBLELEN 12 | ||
| 60 | #define S6_GMAC_MACCONF2_PREAMBLELEN_MASK 0x0F | ||
| 61 | #define S6_GMAC_MACIPGIFG 0x008 | ||
| 62 | #define S6_GMAC_MACIPGIFG_B2BINTERPGAP 0 | ||
| 63 | #define S6_GMAC_MACIPGIFG_B2BINTERPGAP_MASK 0x7F | ||
| 64 | #define S6_GMAC_MACIPGIFG_MINIFGENFORCE 8 | ||
| 65 | #define S6_GMAC_MACIPGIFG_B2BINTERPGAP2 16 | ||
| 66 | #define S6_GMAC_MACIPGIFG_B2BINTERPGAP1 24 | ||
| 67 | #define S6_GMAC_MACHALFDUPLEX 0x00C | ||
| 68 | #define S6_GMAC_MACHALFDUPLEX_COLLISWIN 0 | ||
| 69 | #define S6_GMAC_MACHALFDUPLEX_COLLISWIN_MASK 0x3F | ||
| 70 | #define S6_GMAC_MACHALFDUPLEX_RETXMAX 12 | ||
| 71 | #define S6_GMAC_MACHALFDUPLEX_RETXMAX_MASK 0x0F | ||
| 72 | #define S6_GMAC_MACHALFDUPLEX_EXCESSDEF 16 | ||
| 73 | #define S6_GMAC_MACHALFDUPLEX_NOBACKOFF 17 | ||
| 74 | #define S6_GMAC_MACHALFDUPLEX_BPNOBCKOF 18 | ||
| 75 | #define S6_GMAC_MACHALFDUPLEX_ALTBEBENA 19 | ||
| 76 | #define S6_GMAC_MACHALFDUPLEX_ALTBEBTRN 20 | ||
| 77 | #define S6_GMAC_MACHALFDUPLEX_ALTBEBTR_MASK 0x0F | ||
| 78 | #define S6_GMAC_MACMAXFRAMELEN 0x010 | ||
| 79 | #define S6_GMAC_MACMIICONF 0x020 | ||
| 80 | #define S6_GMAC_MACMIICONF_CSEL 0 | ||
| 81 | #define S6_GMAC_MACMIICONF_CSEL_DIV10 0 | ||
| 82 | #define S6_GMAC_MACMIICONF_CSEL_DIV12 1 | ||
| 83 | #define S6_GMAC_MACMIICONF_CSEL_DIV14 2 | ||
| 84 | #define S6_GMAC_MACMIICONF_CSEL_DIV18 3 | ||
| 85 | #define S6_GMAC_MACMIICONF_CSEL_DIV24 4 | ||
| 86 | #define S6_GMAC_MACMIICONF_CSEL_DIV34 5 | ||
| 87 | #define S6_GMAC_MACMIICONF_CSEL_DIV68 6 | ||
| 88 | #define S6_GMAC_MACMIICONF_CSEL_DIV168 7 | ||
| 89 | #define S6_GMAC_MACMIICONF_CSEL_MASK 7 | ||
| 90 | #define S6_GMAC_MACMIICONF_PREAMBLESUPR 4 | ||
| 91 | #define S6_GMAC_MACMIICONF_SCANAUTOINCR 5 | ||
| 92 | #define S6_GMAC_MACMIICMD 0x024 | ||
| 93 | #define S6_GMAC_MACMIICMD_READ 0 | ||
| 94 | #define S6_GMAC_MACMIICMD_SCAN 1 | ||
| 95 | #define S6_GMAC_MACMIIADDR 0x028 | ||
| 96 | #define S6_GMAC_MACMIIADDR_REG 0 | ||
| 97 | #define S6_GMAC_MACMIIADDR_REG_MASK 0x1F | ||
| 98 | #define S6_GMAC_MACMIIADDR_PHY 8 | ||
| 99 | #define S6_GMAC_MACMIIADDR_PHY_MASK 0x1F | ||
| 100 | #define S6_GMAC_MACMIICTRL 0x02C | ||
| 101 | #define S6_GMAC_MACMIISTAT 0x030 | ||
| 102 | #define S6_GMAC_MACMIIINDI 0x034 | ||
| 103 | #define S6_GMAC_MACMIIINDI_BUSY 0 | ||
| 104 | #define S6_GMAC_MACMIIINDI_SCAN 1 | ||
| 105 | #define S6_GMAC_MACMIIINDI_INVAL 2 | ||
| 106 | #define S6_GMAC_MACINTERFSTAT 0x03C | ||
| 107 | #define S6_GMAC_MACINTERFSTAT_LINKFAIL 3 | ||
| 108 | #define S6_GMAC_MACINTERFSTAT_EXCESSDEF 9 | ||
| 109 | #define S6_GMAC_MACSTATADDR1 0x040 | ||
| 110 | #define S6_GMAC_MACSTATADDR2 0x044 | ||
| 111 | |||
| 112 | #define S6_GMAC_FIFOCONF0 0x048 | ||
| 113 | #define S6_GMAC_FIFOCONF0_HSTRSTWT 0 | ||
| 114 | #define S6_GMAC_FIFOCONF0_HSTRSTSR 1 | ||
| 115 | #define S6_GMAC_FIFOCONF0_HSTRSTFR 2 | ||
| 116 | #define S6_GMAC_FIFOCONF0_HSTRSTST 3 | ||
| 117 | #define S6_GMAC_FIFOCONF0_HSTRSTFT 4 | ||
| 118 | #define S6_GMAC_FIFOCONF0_WTMENREQ 8 | ||
| 119 | #define S6_GMAC_FIFOCONF0_SRFENREQ 9 | ||
| 120 | #define S6_GMAC_FIFOCONF0_FRFENREQ 10 | ||
| 121 | #define S6_GMAC_FIFOCONF0_STFENREQ 11 | ||
| 122 | #define S6_GMAC_FIFOCONF0_FTFENREQ 12 | ||
| 123 | #define S6_GMAC_FIFOCONF0_WTMENRPLY 16 | ||
| 124 | #define S6_GMAC_FIFOCONF0_SRFENRPLY 17 | ||
| 125 | #define S6_GMAC_FIFOCONF0_FRFENRPLY 18 | ||
| 126 | #define S6_GMAC_FIFOCONF0_STFENRPLY 19 | ||
| 127 | #define S6_GMAC_FIFOCONF0_FTFENRPLY 20 | ||
| 128 | #define S6_GMAC_FIFOCONF1 0x04C | ||
| 129 | #define S6_GMAC_FIFOCONF2 0x050 | ||
| 130 | #define S6_GMAC_FIFOCONF2_CFGLWM 0 | ||
| 131 | #define S6_GMAC_FIFOCONF2_CFGHWM 16 | ||
| 132 | #define S6_GMAC_FIFOCONF3 0x054 | ||
| 133 | #define S6_GMAC_FIFOCONF3_CFGFTTH 0 | ||
| 134 | #define S6_GMAC_FIFOCONF3_CFGHWMFT 16 | ||
| 135 | #define S6_GMAC_FIFOCONF4 0x058 | ||
| 136 | #define S6_GMAC_FIFOCONF_RSV_PREVDROP 0 | ||
| 137 | #define S6_GMAC_FIFOCONF_RSV_RUNT 1 | ||
| 138 | #define S6_GMAC_FIFOCONF_RSV_FALSECAR 2 | ||
| 139 | #define S6_GMAC_FIFOCONF_RSV_CODEERR 3 | ||
| 140 | #define S6_GMAC_FIFOCONF_RSV_CRCERR 4 | ||
| 141 | #define S6_GMAC_FIFOCONF_RSV_LENGTHERR 5 | ||
| 142 | #define S6_GMAC_FIFOCONF_RSV_LENRANGE 6 | ||
| 143 | #define S6_GMAC_FIFOCONF_RSV_OK 7 | ||
| 144 | #define S6_GMAC_FIFOCONF_RSV_MULTICAST 8 | ||
| 145 | #define S6_GMAC_FIFOCONF_RSV_BROADCAST 9 | ||
| 146 | #define S6_GMAC_FIFOCONF_RSV_DRIBBLE 10 | ||
| 147 | #define S6_GMAC_FIFOCONF_RSV_CTRLFRAME 11 | ||
| 148 | #define S6_GMAC_FIFOCONF_RSV_PAUSECTRL 12 | ||
| 149 | #define S6_GMAC_FIFOCONF_RSV_UNOPCODE 13 | ||
| 150 | #define S6_GMAC_FIFOCONF_RSV_VLANTAG 14 | ||
| 151 | #define S6_GMAC_FIFOCONF_RSV_LONGEVENT 15 | ||
| 152 | #define S6_GMAC_FIFOCONF_RSV_TRUNCATED 16 | ||
| 153 | #define S6_GMAC_FIFOCONF_RSV_MASK 0x3FFFF | ||
| 154 | #define S6_GMAC_FIFOCONF5 0x05C | ||
| 155 | #define S6_GMAC_FIFOCONF5_DROPLT64 18 | ||
| 156 | #define S6_GMAC_FIFOCONF5_CFGBYTM 19 | ||
| 157 | #define S6_GMAC_FIFOCONF5_RXDROPSIZE 20 | ||
| 158 | #define S6_GMAC_FIFOCONF5_RXDROPSIZE_MASK 0xF | ||
| 159 | |||
| 160 | #define S6_GMAC_STAT_REGS 0x080 | ||
| 161 | #define S6_GMAC_STAT_SIZE_MIN 12 | ||
| 162 | #define S6_GMAC_STATTR64 0x080 | ||
| 163 | #define S6_GMAC_STATTR64_SIZE 18 | ||
| 164 | #define S6_GMAC_STATTR127 0x084 | ||
| 165 | #define S6_GMAC_STATTR127_SIZE 18 | ||
| 166 | #define S6_GMAC_STATTR255 0x088 | ||
| 167 | #define S6_GMAC_STATTR255_SIZE 18 | ||
| 168 | #define S6_GMAC_STATTR511 0x08C | ||
| 169 | #define S6_GMAC_STATTR511_SIZE 18 | ||
| 170 | #define S6_GMAC_STATTR1K 0x090 | ||
| 171 | #define S6_GMAC_STATTR1K_SIZE 18 | ||
| 172 | #define S6_GMAC_STATTRMAX 0x094 | ||
| 173 | #define S6_GMAC_STATTRMAX_SIZE 18 | ||
| 174 | #define S6_GMAC_STATTRMGV 0x098 | ||
| 175 | #define S6_GMAC_STATTRMGV_SIZE 18 | ||
| 176 | #define S6_GMAC_STATRBYT 0x09C | ||
| 177 | #define S6_GMAC_STATRBYT_SIZE 24 | ||
| 178 | #define S6_GMAC_STATRPKT 0x0A0 | ||
| 179 | #define S6_GMAC_STATRPKT_SIZE 18 | ||
| 180 | #define S6_GMAC_STATRFCS 0x0A4 | ||
| 181 | #define S6_GMAC_STATRFCS_SIZE 12 | ||
| 182 | #define S6_GMAC_STATRMCA 0x0A8 | ||
| 183 | #define S6_GMAC_STATRMCA_SIZE 18 | ||
| 184 | #define S6_GMAC_STATRBCA 0x0AC | ||
| 185 | #define S6_GMAC_STATRBCA_SIZE 22 | ||
| 186 | #define S6_GMAC_STATRXCF 0x0B0 | ||
| 187 | #define S6_GMAC_STATRXCF_SIZE 18 | ||
| 188 | #define S6_GMAC_STATRXPF 0x0B4 | ||
| 189 | #define S6_GMAC_STATRXPF_SIZE 12 | ||
| 190 | #define S6_GMAC_STATRXUO 0x0B8 | ||
| 191 | #define S6_GMAC_STATRXUO_SIZE 12 | ||
| 192 | #define S6_GMAC_STATRALN 0x0BC | ||
| 193 | #define S6_GMAC_STATRALN_SIZE 12 | ||
| 194 | #define S6_GMAC_STATRFLR 0x0C0 | ||
| 195 | #define S6_GMAC_STATRFLR_SIZE 16 | ||
| 196 | #define S6_GMAC_STATRCDE 0x0C4 | ||
| 197 | #define S6_GMAC_STATRCDE_SIZE 12 | ||
| 198 | #define S6_GMAC_STATRCSE 0x0C8 | ||
| 199 | #define S6_GMAC_STATRCSE_SIZE 12 | ||
| 200 | #define S6_GMAC_STATRUND 0x0CC | ||
| 201 | #define S6_GMAC_STATRUND_SIZE 12 | ||
| 202 | #define S6_GMAC_STATROVR 0x0D0 | ||
| 203 | #define S6_GMAC_STATROVR_SIZE 12 | ||
| 204 | #define S6_GMAC_STATRFRG 0x0D4 | ||
| 205 | #define S6_GMAC_STATRFRG_SIZE 12 | ||
| 206 | #define S6_GMAC_STATRJBR 0x0D8 | ||
| 207 | #define S6_GMAC_STATRJBR_SIZE 12 | ||
| 208 | #define S6_GMAC_STATRDRP 0x0DC | ||
| 209 | #define S6_GMAC_STATRDRP_SIZE 12 | ||
| 210 | #define S6_GMAC_STATTBYT 0x0E0 | ||
| 211 | #define S6_GMAC_STATTBYT_SIZE 24 | ||
| 212 | #define S6_GMAC_STATTPKT 0x0E4 | ||
| 213 | #define S6_GMAC_STATTPKT_SIZE 18 | ||
| 214 | #define S6_GMAC_STATTMCA 0x0E8 | ||
| 215 | #define S6_GMAC_STATTMCA_SIZE 18 | ||
| 216 | #define S6_GMAC_STATTBCA 0x0EC | ||
| 217 | #define S6_GMAC_STATTBCA_SIZE 18 | ||
| 218 | #define S6_GMAC_STATTXPF 0x0F0 | ||
| 219 | #define S6_GMAC_STATTXPF_SIZE 12 | ||
| 220 | #define S6_GMAC_STATTDFR 0x0F4 | ||
| 221 | #define S6_GMAC_STATTDFR_SIZE 12 | ||
| 222 | #define S6_GMAC_STATTEDF 0x0F8 | ||
| 223 | #define S6_GMAC_STATTEDF_SIZE 12 | ||
| 224 | #define S6_GMAC_STATTSCL 0x0FC | ||
| 225 | #define S6_GMAC_STATTSCL_SIZE 12 | ||
| 226 | #define S6_GMAC_STATTMCL 0x100 | ||
| 227 | #define S6_GMAC_STATTMCL_SIZE 12 | ||
| 228 | #define S6_GMAC_STATTLCL 0x104 | ||
| 229 | #define S6_GMAC_STATTLCL_SIZE 12 | ||
| 230 | #define S6_GMAC_STATTXCL 0x108 | ||
| 231 | #define S6_GMAC_STATTXCL_SIZE 12 | ||
| 232 | #define S6_GMAC_STATTNCL 0x10C | ||
| 233 | #define S6_GMAC_STATTNCL_SIZE 13 | ||
| 234 | #define S6_GMAC_STATTPFH 0x110 | ||
| 235 | #define S6_GMAC_STATTPFH_SIZE 12 | ||
| 236 | #define S6_GMAC_STATTDRP 0x114 | ||
| 237 | #define S6_GMAC_STATTDRP_SIZE 12 | ||
| 238 | #define S6_GMAC_STATTJBR 0x118 | ||
| 239 | #define S6_GMAC_STATTJBR_SIZE 12 | ||
| 240 | #define S6_GMAC_STATTFCS 0x11C | ||
| 241 | #define S6_GMAC_STATTFCS_SIZE 12 | ||
| 242 | #define S6_GMAC_STATTXCF 0x120 | ||
| 243 | #define S6_GMAC_STATTXCF_SIZE 12 | ||
| 244 | #define S6_GMAC_STATTOVR 0x124 | ||
| 245 | #define S6_GMAC_STATTOVR_SIZE 12 | ||
| 246 | #define S6_GMAC_STATTUND 0x128 | ||
| 247 | #define S6_GMAC_STATTUND_SIZE 12 | ||
| 248 | #define S6_GMAC_STATTFRG 0x12C | ||
| 249 | #define S6_GMAC_STATTFRG_SIZE 12 | ||
| 250 | #define S6_GMAC_STATCARRY(n) (0x130 + 4*(n)) | ||
| 251 | #define S6_GMAC_STATCARRYMSK(n) (0x138 + 4*(n)) | ||
| 252 | #define S6_GMAC_STATCARRY1_RDRP 0 | ||
| 253 | #define S6_GMAC_STATCARRY1_RJBR 1 | ||
| 254 | #define S6_GMAC_STATCARRY1_RFRG 2 | ||
| 255 | #define S6_GMAC_STATCARRY1_ROVR 3 | ||
| 256 | #define S6_GMAC_STATCARRY1_RUND 4 | ||
| 257 | #define S6_GMAC_STATCARRY1_RCSE 5 | ||
| 258 | #define S6_GMAC_STATCARRY1_RCDE 6 | ||
| 259 | #define S6_GMAC_STATCARRY1_RFLR 7 | ||
| 260 | #define S6_GMAC_STATCARRY1_RALN 8 | ||
| 261 | #define S6_GMAC_STATCARRY1_RXUO 9 | ||
| 262 | #define S6_GMAC_STATCARRY1_RXPF 10 | ||
| 263 | #define S6_GMAC_STATCARRY1_RXCF 11 | ||
| 264 | #define S6_GMAC_STATCARRY1_RBCA 12 | ||
| 265 | #define S6_GMAC_STATCARRY1_RMCA 13 | ||
| 266 | #define S6_GMAC_STATCARRY1_RFCS 14 | ||
| 267 | #define S6_GMAC_STATCARRY1_RPKT 15 | ||
| 268 | #define S6_GMAC_STATCARRY1_RBYT 16 | ||
| 269 | #define S6_GMAC_STATCARRY1_TRMGV 25 | ||
| 270 | #define S6_GMAC_STATCARRY1_TRMAX 26 | ||
| 271 | #define S6_GMAC_STATCARRY1_TR1K 27 | ||
| 272 | #define S6_GMAC_STATCARRY1_TR511 28 | ||
| 273 | #define S6_GMAC_STATCARRY1_TR255 29 | ||
| 274 | #define S6_GMAC_STATCARRY1_TR127 30 | ||
| 275 | #define S6_GMAC_STATCARRY1_TR64 31 | ||
| 276 | #define S6_GMAC_STATCARRY2_TDRP 0 | ||
| 277 | #define S6_GMAC_STATCARRY2_TPFH 1 | ||
| 278 | #define S6_GMAC_STATCARRY2_TNCL 2 | ||
| 279 | #define S6_GMAC_STATCARRY2_TXCL 3 | ||
| 280 | #define S6_GMAC_STATCARRY2_TLCL 4 | ||
| 281 | #define S6_GMAC_STATCARRY2_TMCL 5 | ||
| 282 | #define S6_GMAC_STATCARRY2_TSCL 6 | ||
| 283 | #define S6_GMAC_STATCARRY2_TEDF 7 | ||
| 284 | #define S6_GMAC_STATCARRY2_TDFR 8 | ||
| 285 | #define S6_GMAC_STATCARRY2_TXPF 9 | ||
| 286 | #define S6_GMAC_STATCARRY2_TBCA 10 | ||
| 287 | #define S6_GMAC_STATCARRY2_TMCA 11 | ||
| 288 | #define S6_GMAC_STATCARRY2_TPKT 12 | ||
| 289 | #define S6_GMAC_STATCARRY2_TBYT 13 | ||
| 290 | #define S6_GMAC_STATCARRY2_TFRG 14 | ||
| 291 | #define S6_GMAC_STATCARRY2_TUND 15 | ||
| 292 | #define S6_GMAC_STATCARRY2_TOVR 16 | ||
| 293 | #define S6_GMAC_STATCARRY2_TXCF 17 | ||
| 294 | #define S6_GMAC_STATCARRY2_TFCS 18 | ||
| 295 | #define S6_GMAC_STATCARRY2_TJBR 19 | ||
| 296 | |||
| 297 | #define S6_GMAC_HOST_PBLKCTRL 0x140 | ||
| 298 | #define S6_GMAC_HOST_PBLKCTRL_TXENA 0 | ||
| 299 | #define S6_GMAC_HOST_PBLKCTRL_RXENA 1 | ||
| 300 | #define S6_GMAC_HOST_PBLKCTRL_TXSRES 2 | ||
| 301 | #define S6_GMAC_HOST_PBLKCTRL_RXSRES 3 | ||
| 302 | #define S6_GMAC_HOST_PBLKCTRL_TXBSIZ 8 | ||
| 303 | #define S6_GMAC_HOST_PBLKCTRL_RXBSIZ 12 | ||
| 304 | #define S6_GMAC_HOST_PBLKCTRL_SIZ_16 4 | ||
| 305 | #define S6_GMAC_HOST_PBLKCTRL_SIZ_32 5 | ||
| 306 | #define S6_GMAC_HOST_PBLKCTRL_SIZ_64 6 | ||
| 307 | #define S6_GMAC_HOST_PBLKCTRL_SIZ_128 7 | ||
| 308 | #define S6_GMAC_HOST_PBLKCTRL_SIZ_MASK 0xF | ||
| 309 | #define S6_GMAC_HOST_PBLKCTRL_STATENA 16 | ||
| 310 | #define S6_GMAC_HOST_PBLKCTRL_STATAUTOZ 17 | ||
| 311 | #define S6_GMAC_HOST_PBLKCTRL_STATCLEAR 18 | ||
| 312 | #define S6_GMAC_HOST_PBLKCTRL_RGMII 19 | ||
| 313 | #define S6_GMAC_HOST_INTMASK 0x144 | ||
| 314 | #define S6_GMAC_HOST_INTSTAT 0x148 | ||
| 315 | #define S6_GMAC_HOST_INT_TXBURSTOVER 3 | ||
| 316 | #define S6_GMAC_HOST_INT_TXPREWOVER 4 | ||
| 317 | #define S6_GMAC_HOST_INT_RXBURSTUNDER 5 | ||
| 318 | #define S6_GMAC_HOST_INT_RXPOSTRFULL 6 | ||
| 319 | #define S6_GMAC_HOST_INT_RXPOSTRUNDER 7 | ||
| 320 | #define S6_GMAC_HOST_RXFIFOHWM 0x14C | ||
| 321 | #define S6_GMAC_HOST_CTRLFRAMXP 0x150 | ||
| 322 | #define S6_GMAC_HOST_DSTADDRLO(n) (0x160 + 8*(n)) | ||
| 323 | #define S6_GMAC_HOST_DSTADDRHI(n) (0x164 + 8*(n)) | ||
| 324 | #define S6_GMAC_HOST_DSTMASKLO(n) (0x180 + 8*(n)) | ||
| 325 | #define S6_GMAC_HOST_DSTMASKHI(n) (0x184 + 8*(n)) | ||
| 326 | |||
| 327 | #define S6_GMAC_BURST_PREWR 0x1B0 | ||
| 328 | #define S6_GMAC_BURST_PREWR_LEN 0 | ||
| 329 | #define S6_GMAC_BURST_PREWR_LEN_MASK ((1 << 20) - 1) | ||
| 330 | #define S6_GMAC_BURST_PREWR_CFE 20 | ||
| 331 | #define S6_GMAC_BURST_PREWR_PPE 21 | ||
| 332 | #define S6_GMAC_BURST_PREWR_FCS 22 | ||
| 333 | #define S6_GMAC_BURST_PREWR_PAD 23 | ||
| 334 | #define S6_GMAC_BURST_POSTRD 0x1D0 | ||
| 335 | #define S6_GMAC_BURST_POSTRD_LEN 0 | ||
| 336 | #define S6_GMAC_BURST_POSTRD_LEN_MASK ((1 << 20) - 1) | ||
| 337 | #define S6_GMAC_BURST_POSTRD_DROP 20 | ||
| 338 | |||
| 339 | |||
| 340 | /* data handling */ | ||
| 341 | |||
| 342 | #define S6_NUM_TX_SKB 8 /* must be larger than TX fifo size */ | ||
| 343 | #define S6_NUM_RX_SKB 16 | ||
| 344 | #define S6_MAX_FRLEN 1536 | ||
| 345 | |||
| 346 | struct s6gmac { | ||
| 347 | u32 reg; | ||
| 348 | u32 tx_dma; | ||
| 349 | u32 rx_dma; | ||
| 350 | u32 io; | ||
| 351 | u8 tx_chan; | ||
| 352 | u8 rx_chan; | ||
| 353 | spinlock_t lock; | ||
| 354 | u8 tx_skb_i, tx_skb_o; | ||
| 355 | u8 rx_skb_i, rx_skb_o; | ||
| 356 | struct sk_buff *tx_skb[S6_NUM_TX_SKB]; | ||
| 357 | struct sk_buff *rx_skb[S6_NUM_RX_SKB]; | ||
| 358 | unsigned long carry[sizeof(struct net_device_stats) / sizeof(long)]; | ||
| 359 | unsigned long stats[sizeof(struct net_device_stats) / sizeof(long)]; | ||
| 360 | struct phy_device *phydev; | ||
| 361 | struct { | ||
| 362 | struct mii_bus *bus; | ||
| 363 | int irq[PHY_MAX_ADDR]; | ||
| 364 | } mii; | ||
| 365 | struct { | ||
| 366 | unsigned int mbit; | ||
| 367 | u8 giga; | ||
| 368 | u8 isup; | ||
| 369 | u8 full; | ||
| 370 | } link; | ||
| 371 | }; | ||
| 372 | |||
| 373 | static void s6gmac_rx_fillfifo(struct s6gmac *pd) | ||
| 374 | { | ||
| 375 | struct sk_buff *skb; | ||
| 376 | while ((((u8)(pd->rx_skb_i - pd->rx_skb_o)) < S6_NUM_RX_SKB) | ||
| 377 | && (!s6dmac_fifo_full(pd->rx_dma, pd->rx_chan)) | ||
| 378 | && (skb = dev_alloc_skb(S6_MAX_FRLEN + 2))) { | ||
| 379 | pd->rx_skb[(pd->rx_skb_i++) % S6_NUM_RX_SKB] = skb; | ||
| 380 | s6dmac_put_fifo_cache(pd->rx_dma, pd->rx_chan, | ||
| 381 | pd->io, (u32)skb->data, S6_MAX_FRLEN); | ||
| 382 | } | ||
| 383 | } | ||
| 384 | |||
| 385 | static void s6gmac_rx_interrupt(struct net_device *dev) | ||
| 386 | { | ||
| 387 | struct s6gmac *pd = netdev_priv(dev); | ||
| 388 | u32 pfx; | ||
| 389 | struct sk_buff *skb; | ||
| 390 | while (((u8)(pd->rx_skb_i - pd->rx_skb_o)) > | ||
| 391 | s6dmac_pending_count(pd->rx_dma, pd->rx_chan)) { | ||
| 392 | skb = pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]; | ||
| 393 | pfx = readl(pd->reg + S6_GMAC_BURST_POSTRD); | ||
| 394 | if (pfx & (1 << S6_GMAC_BURST_POSTRD_DROP)) { | ||
| 395 | dev_kfree_skb_irq(skb); | ||
| 396 | } else { | ||
| 397 | skb_put(skb, (pfx >> S6_GMAC_BURST_POSTRD_LEN) | ||
| 398 | & S6_GMAC_BURST_POSTRD_LEN_MASK); | ||
| 399 | skb->dev = dev; | ||
| 400 | skb->protocol = eth_type_trans(skb, dev); | ||
| 401 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 402 | netif_rx(skb); | ||
| 403 | } | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | static void s6gmac_tx_interrupt(struct net_device *dev) | ||
| 408 | { | ||
| 409 | struct s6gmac *pd = netdev_priv(dev); | ||
| 410 | while (((u8)(pd->tx_skb_i - pd->tx_skb_o)) > | ||
| 411 | s6dmac_pending_count(pd->tx_dma, pd->tx_chan)) { | ||
| 412 | dev_kfree_skb_irq(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); | ||
| 413 | } | ||
| 414 | if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) | ||
| 415 | netif_wake_queue(dev); | ||
| 416 | } | ||
| 417 | |||
| 418 | struct s6gmac_statinf { | ||
| 419 | unsigned reg_size : 4; /* 0: unused */ | ||
| 420 | unsigned reg_off : 6; | ||
| 421 | unsigned net_index : 6; | ||
| 422 | }; | ||
| 423 | |||
| 424 | #define S6_STATS_B (8 * sizeof(u32)) | ||
| 425 | #define S6_STATS_C(b, r, f) [b] = { \ | ||
| 426 | BUILD_BUG_ON_ZERO(r##_SIZE < S6_GMAC_STAT_SIZE_MIN) + \ | ||
| 427 | BUILD_BUG_ON_ZERO((r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1)) \ | ||
| 428 | >= (1<<4)) + \ | ||
| 429 | r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1), \ | ||
| 430 | BUILD_BUG_ON_ZERO(((unsigned)((r - S6_GMAC_STAT_REGS) / sizeof(u32))) \ | ||
| 431 | >= ((1<<6)-1)) + \ | ||
| 432 | (r - S6_GMAC_STAT_REGS) / sizeof(u32), \ | ||
| 433 | BUILD_BUG_ON_ZERO((offsetof(struct net_device_stats, f)) \ | ||
| 434 | % sizeof(unsigned long)) + \ | ||
| 435 | BUILD_BUG_ON_ZERO((((unsigned)(offsetof(struct net_device_stats, f)) \ | ||
| 436 | / sizeof(unsigned long)) >= (1<<6))) + \ | ||
| 437 | BUILD_BUG_ON_ZERO((sizeof(((struct net_device_stats *)0)->f) \ | ||
| 438 | != sizeof(unsigned long))) + \ | ||
| 439 | (offsetof(struct net_device_stats, f)) / sizeof(unsigned long)}, | ||
| 440 | |||
| 441 | static const struct s6gmac_statinf statinf[2][S6_STATS_B] = { { | ||
| 442 | S6_STATS_C(S6_GMAC_STATCARRY1_RBYT, S6_GMAC_STATRBYT, rx_bytes) | ||
| 443 | S6_STATS_C(S6_GMAC_STATCARRY1_RPKT, S6_GMAC_STATRPKT, rx_packets) | ||
| 444 | S6_STATS_C(S6_GMAC_STATCARRY1_RFCS, S6_GMAC_STATRFCS, rx_crc_errors) | ||
| 445 | S6_STATS_C(S6_GMAC_STATCARRY1_RMCA, S6_GMAC_STATRMCA, multicast) | ||
| 446 | S6_STATS_C(S6_GMAC_STATCARRY1_RALN, S6_GMAC_STATRALN, rx_frame_errors) | ||
| 447 | S6_STATS_C(S6_GMAC_STATCARRY1_RFLR, S6_GMAC_STATRFLR, rx_length_errors) | ||
| 448 | S6_STATS_C(S6_GMAC_STATCARRY1_RCDE, S6_GMAC_STATRCDE, rx_missed_errors) | ||
| 449 | S6_STATS_C(S6_GMAC_STATCARRY1_RUND, S6_GMAC_STATRUND, rx_length_errors) | ||
| 450 | S6_STATS_C(S6_GMAC_STATCARRY1_ROVR, S6_GMAC_STATROVR, rx_length_errors) | ||
| 451 | S6_STATS_C(S6_GMAC_STATCARRY1_RFRG, S6_GMAC_STATRFRG, rx_crc_errors) | ||
| 452 | S6_STATS_C(S6_GMAC_STATCARRY1_RJBR, S6_GMAC_STATRJBR, rx_crc_errors) | ||
| 453 | S6_STATS_C(S6_GMAC_STATCARRY1_RDRP, S6_GMAC_STATRDRP, rx_dropped) | ||
| 454 | }, { | ||
| 455 | S6_STATS_C(S6_GMAC_STATCARRY2_TBYT, S6_GMAC_STATTBYT, tx_bytes) | ||
| 456 | S6_STATS_C(S6_GMAC_STATCARRY2_TPKT, S6_GMAC_STATTPKT, tx_packets) | ||
| 457 | S6_STATS_C(S6_GMAC_STATCARRY2_TEDF, S6_GMAC_STATTEDF, tx_aborted_errors) | ||
| 458 | S6_STATS_C(S6_GMAC_STATCARRY2_TXCL, S6_GMAC_STATTXCL, tx_aborted_errors) | ||
| 459 | S6_STATS_C(S6_GMAC_STATCARRY2_TNCL, S6_GMAC_STATTNCL, collisions) | ||
| 460 | S6_STATS_C(S6_GMAC_STATCARRY2_TDRP, S6_GMAC_STATTDRP, tx_dropped) | ||
| 461 | S6_STATS_C(S6_GMAC_STATCARRY2_TJBR, S6_GMAC_STATTJBR, tx_errors) | ||
| 462 | S6_STATS_C(S6_GMAC_STATCARRY2_TFCS, S6_GMAC_STATTFCS, tx_errors) | ||
| 463 | S6_STATS_C(S6_GMAC_STATCARRY2_TOVR, S6_GMAC_STATTOVR, tx_errors) | ||
| 464 | S6_STATS_C(S6_GMAC_STATCARRY2_TUND, S6_GMAC_STATTUND, tx_errors) | ||
| 465 | S6_STATS_C(S6_GMAC_STATCARRY2_TFRG, S6_GMAC_STATTFRG, tx_errors) | ||
| 466 | } }; | ||
| 467 | |||
| 468 | static void s6gmac_stats_collect(struct s6gmac *pd, | ||
| 469 | const struct s6gmac_statinf *inf) | ||
| 470 | { | ||
| 471 | int b; | ||
| 472 | for (b = 0; b < S6_STATS_B; b++) { | ||
| 473 | if (inf[b].reg_size) { | ||
| 474 | pd->stats[inf[b].net_index] += | ||
| 475 | readl(pd->reg + S6_GMAC_STAT_REGS | ||
| 476 | + sizeof(u32) * inf[b].reg_off); | ||
| 477 | } | ||
| 478 | } | ||
| 479 | } | ||
| 480 | |||
| 481 | static void s6gmac_stats_carry(struct s6gmac *pd, | ||
| 482 | const struct s6gmac_statinf *inf, u32 mask) | ||
| 483 | { | ||
| 484 | int b; | ||
| 485 | while (mask) { | ||
| 486 | b = fls(mask) - 1; | ||
| 487 | mask &= ~(1 << b); | ||
| 488 | pd->carry[inf[b].net_index] += (1 << inf[b].reg_size); | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | static inline u32 s6gmac_stats_pending(struct s6gmac *pd, int carry) | ||
| 493 | { | ||
| 494 | int r = readl(pd->reg + S6_GMAC_STATCARRY(carry)) & | ||
| 495 | ~readl(pd->reg + S6_GMAC_STATCARRYMSK(carry)); | ||
| 496 | return r; | ||
| 497 | } | ||
| 498 | |||
| 499 | static inline void s6gmac_stats_interrupt(struct s6gmac *pd, int carry) | ||
| 500 | { | ||
| 501 | u32 mask; | ||
| 502 | mask = s6gmac_stats_pending(pd, carry); | ||
| 503 | if (mask) { | ||
| 504 | writel(mask, pd->reg + S6_GMAC_STATCARRY(carry)); | ||
| 505 | s6gmac_stats_carry(pd, &statinf[carry][0], mask); | ||
| 506 | } | ||
| 507 | } | ||
| 508 | |||
| 509 | static irqreturn_t s6gmac_interrupt(int irq, void *dev_id) | ||
| 510 | { | ||
| 511 | struct net_device *dev = (struct net_device *)dev_id; | ||
| 512 | struct s6gmac *pd = netdev_priv(dev); | ||
| 513 | if (!dev) | ||
| 514 | return IRQ_NONE; | ||
| 515 | spin_lock(&pd->lock); | ||
| 516 | if (s6dmac_termcnt_irq(pd->rx_dma, pd->rx_chan)) | ||
| 517 | s6gmac_rx_interrupt(dev); | ||
| 518 | s6gmac_rx_fillfifo(pd); | ||
| 519 | if (s6dmac_termcnt_irq(pd->tx_dma, pd->tx_chan)) | ||
| 520 | s6gmac_tx_interrupt(dev); | ||
| 521 | s6gmac_stats_interrupt(pd, 0); | ||
| 522 | s6gmac_stats_interrupt(pd, 1); | ||
| 523 | spin_unlock(&pd->lock); | ||
| 524 | return IRQ_HANDLED; | ||
| 525 | } | ||
| 526 | |||
| 527 | static inline void s6gmac_set_dstaddr(struct s6gmac *pd, int n, | ||
| 528 | u32 addrlo, u32 addrhi, u32 masklo, u32 maskhi) | ||
| 529 | { | ||
| 530 | writel(addrlo, pd->reg + S6_GMAC_HOST_DSTADDRLO(n)); | ||
| 531 | writel(addrhi, pd->reg + S6_GMAC_HOST_DSTADDRHI(n)); | ||
| 532 | writel(masklo, pd->reg + S6_GMAC_HOST_DSTMASKLO(n)); | ||
| 533 | writel(maskhi, pd->reg + S6_GMAC_HOST_DSTMASKHI(n)); | ||
| 534 | } | ||
| 535 | |||
| 536 | static inline void s6gmac_stop_device(struct net_device *dev) | ||
| 537 | { | ||
| 538 | struct s6gmac *pd = netdev_priv(dev); | ||
| 539 | writel(0, pd->reg + S6_GMAC_MACCONF1); | ||
| 540 | } | ||
| 541 | |||
| 542 | static inline void s6gmac_init_device(struct net_device *dev) | ||
| 543 | { | ||
| 544 | struct s6gmac *pd = netdev_priv(dev); | ||
| 545 | int is_rgmii = !!(pd->phydev->supported | ||
| 546 | & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)); | ||
| 547 | #if 0 | ||
| 548 | writel(1 << S6_GMAC_MACCONF1_SYNCTX | | ||
| 549 | 1 << S6_GMAC_MACCONF1_SYNCRX | | ||
| 550 | 1 << S6_GMAC_MACCONF1_TXFLOWCTRL | | ||
| 551 | 1 << S6_GMAC_MACCONF1_RXFLOWCTRL | | ||
| 552 | 1 << S6_GMAC_MACCONF1_RESTXFUNC | | ||
| 553 | 1 << S6_GMAC_MACCONF1_RESRXFUNC | | ||
| 554 | 1 << S6_GMAC_MACCONF1_RESTXMACCTRL | | ||
| 555 | 1 << S6_GMAC_MACCONF1_RESRXMACCTRL, | ||
| 556 | pd->reg + S6_GMAC_MACCONF1); | ||
| 557 | #endif | ||
| 558 | writel(1 << S6_GMAC_MACCONF1_SOFTRES, pd->reg + S6_GMAC_MACCONF1); | ||
| 559 | udelay(1000); | ||
| 560 | writel(1 << S6_GMAC_MACCONF1_TXENA | 1 << S6_GMAC_MACCONF1_RXENA, | ||
| 561 | pd->reg + S6_GMAC_MACCONF1); | ||
| 562 | writel(1 << S6_GMAC_HOST_PBLKCTRL_TXSRES | | ||
| 563 | 1 << S6_GMAC_HOST_PBLKCTRL_RXSRES, | ||
| 564 | pd->reg + S6_GMAC_HOST_PBLKCTRL); | ||
| 565 | writel(S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | | ||
| 566 | S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | | ||
| 567 | 1 << S6_GMAC_HOST_PBLKCTRL_STATENA | | ||
| 568 | 1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | | ||
| 569 | is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, | ||
| 570 | pd->reg + S6_GMAC_HOST_PBLKCTRL); | ||
| 571 | writel(1 << S6_GMAC_MACCONF1_TXENA | | ||
| 572 | 1 << S6_GMAC_MACCONF1_RXENA | | ||
| 573 | (dev->flags & IFF_LOOPBACK ? 1 : 0) | ||
| 574 | << S6_GMAC_MACCONF1_LOOPBACK, | ||
| 575 | pd->reg + S6_GMAC_MACCONF1); | ||
| 576 | writel(dev->mtu && (dev->mtu < (S6_MAX_FRLEN - ETH_HLEN-ETH_FCS_LEN)) ? | ||
| 577 | dev->mtu+ETH_HLEN+ETH_FCS_LEN : S6_MAX_FRLEN, | ||
| 578 | pd->reg + S6_GMAC_MACMAXFRAMELEN); | ||
| 579 | writel((pd->link.full ? 1 : 0) << S6_GMAC_MACCONF2_FULL | | ||
| 580 | 1 << S6_GMAC_MACCONF2_PADCRCENA | | ||
| 581 | 1 << S6_GMAC_MACCONF2_LENGTHFCHK | | ||
| 582 | (pd->link.giga ? | ||
| 583 | S6_GMAC_MACCONF2_IFMODE_BYTE : | ||
| 584 | S6_GMAC_MACCONF2_IFMODE_NIBBLE) | ||
| 585 | << S6_GMAC_MACCONF2_IFMODE | | ||
| 586 | 7 << S6_GMAC_MACCONF2_PREAMBLELEN, | ||
| 587 | pd->reg + S6_GMAC_MACCONF2); | ||
| 588 | writel(0, pd->reg + S6_GMAC_MACSTATADDR1); | ||
| 589 | writel(0, pd->reg + S6_GMAC_MACSTATADDR2); | ||
| 590 | writel(1 << S6_GMAC_FIFOCONF0_WTMENREQ | | ||
| 591 | 1 << S6_GMAC_FIFOCONF0_SRFENREQ | | ||
| 592 | 1 << S6_GMAC_FIFOCONF0_FRFENREQ | | ||
| 593 | 1 << S6_GMAC_FIFOCONF0_STFENREQ | | ||
| 594 | 1 << S6_GMAC_FIFOCONF0_FTFENREQ, | ||
| 595 | pd->reg + S6_GMAC_FIFOCONF0); | ||
| 596 | writel(128 << S6_GMAC_FIFOCONF3_CFGFTTH | | ||
| 597 | 128 << S6_GMAC_FIFOCONF3_CFGHWMFT, | ||
| 598 | pd->reg + S6_GMAC_FIFOCONF3); | ||
| 599 | writel((S6_GMAC_FIFOCONF_RSV_MASK & ~( | ||
| 600 | 1 << S6_GMAC_FIFOCONF_RSV_RUNT | | ||
| 601 | 1 << S6_GMAC_FIFOCONF_RSV_CRCERR | | ||
| 602 | 1 << S6_GMAC_FIFOCONF_RSV_OK | | ||
| 603 | 1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | | ||
| 604 | 1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | | ||
| 605 | 1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | | ||
| 606 | 1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | | ||
| 607 | 1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED)) | | ||
| 608 | 1 << S6_GMAC_FIFOCONF5_DROPLT64 | | ||
| 609 | pd->link.giga << S6_GMAC_FIFOCONF5_CFGBYTM | | ||
| 610 | 1 << S6_GMAC_FIFOCONF5_RXDROPSIZE, | ||
| 611 | pd->reg + S6_GMAC_FIFOCONF5); | ||
| 612 | writel(1 << S6_GMAC_FIFOCONF_RSV_RUNT | | ||
| 613 | 1 << S6_GMAC_FIFOCONF_RSV_CRCERR | | ||
| 614 | 1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE | | ||
| 615 | 1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME | | ||
| 616 | 1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL | | ||
| 617 | 1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE | | ||
| 618 | 1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED, | ||
| 619 | pd->reg + S6_GMAC_FIFOCONF4); | ||
| 620 | s6gmac_set_dstaddr(pd, 0, | ||
| 621 | 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF); | ||
| 622 | s6gmac_set_dstaddr(pd, 1, | ||
| 623 | dev->dev_addr[5] | | ||
| 624 | dev->dev_addr[4] << 8 | | ||
| 625 | dev->dev_addr[3] << 16 | | ||
| 626 | dev->dev_addr[2] << 24, | ||
| 627 | dev->dev_addr[1] | | ||
| 628 | dev->dev_addr[0] << 8, | ||
| 629 | 0xFFFFFFFF, 0x0000FFFF); | ||
| 630 | s6gmac_set_dstaddr(pd, 2, | ||
| 631 | 0x00000000, 0x00000100, 0x00000000, 0x00000100); | ||
| 632 | s6gmac_set_dstaddr(pd, 3, | ||
| 633 | 0x00000000, 0x00000000, 0x00000000, 0x00000000); | ||
| 634 | writel(1 << S6_GMAC_HOST_PBLKCTRL_TXENA | | ||
| 635 | 1 << S6_GMAC_HOST_PBLKCTRL_RXENA | | ||
| 636 | S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ | | ||
| 637 | S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ | | ||
| 638 | 1 << S6_GMAC_HOST_PBLKCTRL_STATENA | | ||
| 639 | 1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR | | ||
| 640 | is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII, | ||
| 641 | pd->reg + S6_GMAC_HOST_PBLKCTRL); | ||
| 642 | } | ||
| 643 | |||
| 644 | static void s6mii_enable(struct s6gmac *pd) | ||
| 645 | { | ||
| 646 | writel(readl(pd->reg + S6_GMAC_MACCONF1) & | ||
| 647 | ~(1 << S6_GMAC_MACCONF1_SOFTRES), | ||
| 648 | pd->reg + S6_GMAC_MACCONF1); | ||
| 649 | writel((readl(pd->reg + S6_GMAC_MACMIICONF) | ||
| 650 | & ~(S6_GMAC_MACMIICONF_CSEL_MASK << S6_GMAC_MACMIICONF_CSEL)) | ||
| 651 | | (S6_GMAC_MACMIICONF_CSEL_DIV168 << S6_GMAC_MACMIICONF_CSEL), | ||
| 652 | pd->reg + S6_GMAC_MACMIICONF); | ||
| 653 | } | ||
| 654 | |||
| 655 | static int s6mii_busy(struct s6gmac *pd, int tmo) | ||
| 656 | { | ||
| 657 | while (readl(pd->reg + S6_GMAC_MACMIIINDI)) { | ||
| 658 | if (--tmo == 0) | ||
| 659 | return -ETIME; | ||
| 660 | udelay(64); | ||
| 661 | } | ||
| 662 | return 0; | ||
| 663 | } | ||
| 664 | |||
| 665 | static int s6mii_read(struct mii_bus *bus, int phy_addr, int regnum) | ||
| 666 | { | ||
| 667 | struct s6gmac *pd = bus->priv; | ||
| 668 | s6mii_enable(pd); | ||
| 669 | if (s6mii_busy(pd, 256)) | ||
| 670 | return -ETIME; | ||
| 671 | writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | | ||
| 672 | regnum << S6_GMAC_MACMIIADDR_REG, | ||
| 673 | pd->reg + S6_GMAC_MACMIIADDR); | ||
| 674 | writel(1 << S6_GMAC_MACMIICMD_READ, pd->reg + S6_GMAC_MACMIICMD); | ||
| 675 | writel(0, pd->reg + S6_GMAC_MACMIICMD); | ||
| 676 | if (s6mii_busy(pd, 256)) | ||
| 677 | return -ETIME; | ||
| 678 | return (u16)readl(pd->reg + S6_GMAC_MACMIISTAT); | ||
| 679 | } | ||
| 680 | |||
| 681 | static int s6mii_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value) | ||
| 682 | { | ||
| 683 | struct s6gmac *pd = bus->priv; | ||
| 684 | s6mii_enable(pd); | ||
| 685 | if (s6mii_busy(pd, 256)) | ||
| 686 | return -ETIME; | ||
| 687 | writel(phy_addr << S6_GMAC_MACMIIADDR_PHY | | ||
| 688 | regnum << S6_GMAC_MACMIIADDR_REG, | ||
| 689 | pd->reg + S6_GMAC_MACMIIADDR); | ||
| 690 | writel(value, pd->reg + S6_GMAC_MACMIICTRL); | ||
| 691 | if (s6mii_busy(pd, 256)) | ||
| 692 | return -ETIME; | ||
| 693 | return 0; | ||
| 694 | } | ||
| 695 | |||
| 696 | static int s6mii_reset(struct mii_bus *bus) | ||
| 697 | { | ||
| 698 | struct s6gmac *pd = bus->priv; | ||
| 699 | s6mii_enable(pd); | ||
| 700 | if (s6mii_busy(pd, PHY_INIT_TIMEOUT)) | ||
| 701 | return -ETIME; | ||
| 702 | return 0; | ||
| 703 | } | ||
| 704 | |||
| 705 | static void s6gmac_set_rgmii_txclock(struct s6gmac *pd) | ||
| 706 | { | ||
| 707 | u32 pllsel = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL); | ||
| 708 | pllsel &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC); | ||
| 709 | switch (pd->link.mbit) { | ||
| 710 | case 10: | ||
| 711 | pllsel |= S6_GREG1_PLLSEL_GMAC_2500KHZ << S6_GREG1_PLLSEL_GMAC; | ||
| 712 | break; | ||
| 713 | case 100: | ||
| 714 | pllsel |= S6_GREG1_PLLSEL_GMAC_25MHZ << S6_GREG1_PLLSEL_GMAC; | ||
| 715 | break; | ||
| 716 | case 1000: | ||
| 717 | pllsel |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC; | ||
| 718 | break; | ||
| 719 | default: | ||
| 720 | return; | ||
| 721 | } | ||
| 722 | writel(pllsel, S6_REG_GREG1 + S6_GREG1_PLLSEL); | ||
| 723 | } | ||
| 724 | |||
| 725 | static inline void s6gmac_linkisup(struct net_device *dev, int isup) | ||
| 726 | { | ||
| 727 | struct s6gmac *pd = netdev_priv(dev); | ||
| 728 | struct phy_device *phydev = pd->phydev; | ||
| 729 | |||
| 730 | pd->link.full = phydev->duplex; | ||
| 731 | pd->link.giga = (phydev->speed == 1000); | ||
| 732 | if (pd->link.mbit != phydev->speed) { | ||
| 733 | pd->link.mbit = phydev->speed; | ||
| 734 | s6gmac_set_rgmii_txclock(pd); | ||
| 735 | } | ||
| 736 | pd->link.isup = isup; | ||
| 737 | if (isup) | ||
| 738 | netif_carrier_on(dev); | ||
| 739 | phy_print_status(phydev); | ||
| 740 | } | ||
| 741 | |||
| 742 | static void s6gmac_adjust_link(struct net_device *dev) | ||
| 743 | { | ||
| 744 | struct s6gmac *pd = netdev_priv(dev); | ||
| 745 | struct phy_device *phydev = pd->phydev; | ||
| 746 | if (pd->link.isup && | ||
| 747 | (!phydev->link || | ||
| 748 | (pd->link.mbit != phydev->speed) || | ||
| 749 | (pd->link.full != phydev->duplex))) { | ||
| 750 | pd->link.isup = 0; | ||
| 751 | netif_tx_disable(dev); | ||
| 752 | if (!phydev->link) { | ||
| 753 | netif_carrier_off(dev); | ||
| 754 | phy_print_status(phydev); | ||
| 755 | } | ||
| 756 | } | ||
| 757 | if (!pd->link.isup && phydev->link) { | ||
| 758 | if (pd->link.full != phydev->duplex) { | ||
| 759 | u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); | ||
| 760 | if (phydev->duplex) | ||
| 761 | maccfg |= 1 << S6_GMAC_MACCONF2_FULL; | ||
| 762 | else | ||
| 763 | maccfg &= ~(1 << S6_GMAC_MACCONF2_FULL); | ||
| 764 | writel(maccfg, pd->reg + S6_GMAC_MACCONF2); | ||
| 765 | } | ||
| 766 | |||
| 767 | if (pd->link.giga != (phydev->speed == 1000)) { | ||
| 768 | u32 fifocfg = readl(pd->reg + S6_GMAC_FIFOCONF5); | ||
| 769 | u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2); | ||
| 770 | maccfg &= ~(S6_GMAC_MACCONF2_IFMODE_MASK | ||
| 771 | << S6_GMAC_MACCONF2_IFMODE); | ||
| 772 | if (phydev->speed == 1000) { | ||
| 773 | fifocfg |= 1 << S6_GMAC_FIFOCONF5_CFGBYTM; | ||
| 774 | maccfg |= S6_GMAC_MACCONF2_IFMODE_BYTE | ||
| 775 | << S6_GMAC_MACCONF2_IFMODE; | ||
| 776 | } else { | ||
| 777 | fifocfg &= ~(1 << S6_GMAC_FIFOCONF5_CFGBYTM); | ||
| 778 | maccfg |= S6_GMAC_MACCONF2_IFMODE_NIBBLE | ||
| 779 | << S6_GMAC_MACCONF2_IFMODE; | ||
| 780 | } | ||
| 781 | writel(fifocfg, pd->reg + S6_GMAC_FIFOCONF5); | ||
| 782 | writel(maccfg, pd->reg + S6_GMAC_MACCONF2); | ||
| 783 | } | ||
| 784 | |||
| 785 | if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) | ||
| 786 | netif_wake_queue(dev); | ||
| 787 | s6gmac_linkisup(dev, 1); | ||
| 788 | } | ||
| 789 | } | ||
| 790 | |||
| 791 | static inline int s6gmac_phy_start(struct net_device *dev) | ||
| 792 | { | ||
| 793 | struct s6gmac *pd = netdev_priv(dev); | ||
| 794 | int i = 0; | ||
| 795 | struct phy_device *p = NULL; | ||
| 796 | while ((!(p = pd->mii.bus->phy_map[i])) && (i < PHY_MAX_ADDR)) | ||
| 797 | i++; | ||
| 798 | p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link, 0, | ||
| 799 | PHY_INTERFACE_MODE_RGMII); | ||
| 800 | if (IS_ERR(p)) { | ||
| 801 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | ||
| 802 | return PTR_ERR(p); | ||
| 803 | } | ||
| 804 | p->supported &= PHY_GBIT_FEATURES; | ||
| 805 | p->advertising = p->supported; | ||
| 806 | pd->phydev = p; | ||
| 807 | return 0; | ||
| 808 | } | ||
| 809 | |||
| 810 | static inline void s6gmac_init_stats(struct net_device *dev) | ||
| 811 | { | ||
| 812 | struct s6gmac *pd = netdev_priv(dev); | ||
| 813 | u32 mask; | ||
| 814 | mask = 1 << S6_GMAC_STATCARRY1_RDRP | | ||
| 815 | 1 << S6_GMAC_STATCARRY1_RJBR | | ||
| 816 | 1 << S6_GMAC_STATCARRY1_RFRG | | ||
| 817 | 1 << S6_GMAC_STATCARRY1_ROVR | | ||
| 818 | 1 << S6_GMAC_STATCARRY1_RUND | | ||
| 819 | 1 << S6_GMAC_STATCARRY1_RCDE | | ||
| 820 | 1 << S6_GMAC_STATCARRY1_RFLR | | ||
| 821 | 1 << S6_GMAC_STATCARRY1_RALN | | ||
| 822 | 1 << S6_GMAC_STATCARRY1_RMCA | | ||
| 823 | 1 << S6_GMAC_STATCARRY1_RFCS | | ||
| 824 | 1 << S6_GMAC_STATCARRY1_RPKT | | ||
| 825 | 1 << S6_GMAC_STATCARRY1_RBYT; | ||
| 826 | writel(mask, pd->reg + S6_GMAC_STATCARRY(0)); | ||
| 827 | writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(0)); | ||
| 828 | mask = 1 << S6_GMAC_STATCARRY2_TDRP | | ||
| 829 | 1 << S6_GMAC_STATCARRY2_TNCL | | ||
| 830 | 1 << S6_GMAC_STATCARRY2_TXCL | | ||
| 831 | 1 << S6_GMAC_STATCARRY2_TEDF | | ||
| 832 | 1 << S6_GMAC_STATCARRY2_TPKT | | ||
| 833 | 1 << S6_GMAC_STATCARRY2_TBYT | | ||
| 834 | 1 << S6_GMAC_STATCARRY2_TFRG | | ||
| 835 | 1 << S6_GMAC_STATCARRY2_TUND | | ||
| 836 | 1 << S6_GMAC_STATCARRY2_TOVR | | ||
| 837 | 1 << S6_GMAC_STATCARRY2_TFCS | | ||
| 838 | 1 << S6_GMAC_STATCARRY2_TJBR; | ||
| 839 | writel(mask, pd->reg + S6_GMAC_STATCARRY(1)); | ||
| 840 | writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(1)); | ||
| 841 | } | ||
| 842 | |||
| 843 | static inline void s6gmac_init_dmac(struct net_device *dev) | ||
| 844 | { | ||
| 845 | struct s6gmac *pd = netdev_priv(dev); | ||
| 846 | s6dmac_disable_chan(pd->tx_dma, pd->tx_chan); | ||
| 847 | s6dmac_disable_chan(pd->rx_dma, pd->rx_chan); | ||
| 848 | s6dmac_disable_error_irqs(pd->tx_dma, 1 << S6_HIFDMA_GMACTX); | ||
| 849 | s6dmac_disable_error_irqs(pd->rx_dma, 1 << S6_HIFDMA_GMACRX); | ||
| 850 | } | ||
| 851 | |||
| 852 | static int s6gmac_tx(struct sk_buff *skb, struct net_device *dev) | ||
| 853 | { | ||
| 854 | struct s6gmac *pd = netdev_priv(dev); | ||
| 855 | unsigned long flags; | ||
| 856 | spin_lock_irqsave(&pd->lock, flags); | ||
| 857 | dev->trans_start = jiffies; | ||
| 858 | writel(skb->len << S6_GMAC_BURST_PREWR_LEN | | ||
| 859 | 0 << S6_GMAC_BURST_PREWR_CFE | | ||
| 860 | 1 << S6_GMAC_BURST_PREWR_PPE | | ||
| 861 | 1 << S6_GMAC_BURST_PREWR_FCS | | ||
| 862 | ((skb->len < ETH_ZLEN) ? 1 : 0) << S6_GMAC_BURST_PREWR_PAD, | ||
| 863 | pd->reg + S6_GMAC_BURST_PREWR); | ||
| 864 | s6dmac_put_fifo_cache(pd->tx_dma, pd->tx_chan, | ||
| 865 | (u32)skb->data, pd->io, skb->len); | ||
| 866 | if (s6dmac_fifo_full(pd->tx_dma, pd->tx_chan)) | ||
| 867 | netif_stop_queue(dev); | ||
| 868 | if (((u8)(pd->tx_skb_i - pd->tx_skb_o)) >= S6_NUM_TX_SKB) { | ||
| 869 | printk(KERN_ERR "GMAC BUG: skb tx ring overflow [%x, %x]\n", | ||
| 870 | pd->tx_skb_o, pd->tx_skb_i); | ||
| 871 | BUG(); | ||
| 872 | } | ||
| 873 | pd->tx_skb[(pd->tx_skb_i++) % S6_NUM_TX_SKB] = skb; | ||
| 874 | spin_unlock_irqrestore(&pd->lock, flags); | ||
| 875 | return 0; | ||
| 876 | } | ||
| 877 | |||
| 878 | static void s6gmac_tx_timeout(struct net_device *dev) | ||
| 879 | { | ||
| 880 | struct s6gmac *pd = netdev_priv(dev); | ||
| 881 | unsigned long flags; | ||
| 882 | spin_lock_irqsave(&pd->lock, flags); | ||
| 883 | s6gmac_tx_interrupt(dev); | ||
| 884 | spin_unlock_irqrestore(&pd->lock, flags); | ||
| 885 | } | ||
| 886 | |||
| 887 | static int s6gmac_open(struct net_device *dev) | ||
| 888 | { | ||
| 889 | struct s6gmac *pd = netdev_priv(dev); | ||
| 890 | unsigned long flags; | ||
| 891 | phy_read_status(pd->phydev); | ||
| 892 | spin_lock_irqsave(&pd->lock, flags); | ||
| 893 | pd->link.mbit = 0; | ||
| 894 | s6gmac_linkisup(dev, pd->phydev->link); | ||
| 895 | s6gmac_init_device(dev); | ||
| 896 | s6gmac_init_stats(dev); | ||
| 897 | s6gmac_init_dmac(dev); | ||
| 898 | s6gmac_rx_fillfifo(pd); | ||
| 899 | s6dmac_enable_chan(pd->rx_dma, pd->rx_chan, | ||
| 900 | 2, 1, 0, 1, 0, 0, 0, 7, -1, 2, 0, 1); | ||
| 901 | s6dmac_enable_chan(pd->tx_dma, pd->tx_chan, | ||
| 902 | 2, 0, 1, 0, 0, 0, 0, 7, -1, 2, 0, 1); | ||
| 903 | writel(0 << S6_GMAC_HOST_INT_TXBURSTOVER | | ||
| 904 | 0 << S6_GMAC_HOST_INT_TXPREWOVER | | ||
| 905 | 0 << S6_GMAC_HOST_INT_RXBURSTUNDER | | ||
| 906 | 0 << S6_GMAC_HOST_INT_RXPOSTRFULL | | ||
| 907 | 0 << S6_GMAC_HOST_INT_RXPOSTRUNDER, | ||
| 908 | pd->reg + S6_GMAC_HOST_INTMASK); | ||
| 909 | spin_unlock_irqrestore(&pd->lock, flags); | ||
| 910 | phy_start(pd->phydev); | ||
| 911 | netif_start_queue(dev); | ||
| 912 | return 0; | ||
| 913 | } | ||
| 914 | |||
| 915 | static int s6gmac_stop(struct net_device *dev) | ||
| 916 | { | ||
| 917 | struct s6gmac *pd = netdev_priv(dev); | ||
| 918 | unsigned long flags; | ||
| 919 | netif_stop_queue(dev); | ||
| 920 | phy_stop(pd->phydev); | ||
| 921 | spin_lock_irqsave(&pd->lock, flags); | ||
| 922 | s6gmac_init_dmac(dev); | ||
| 923 | s6gmac_stop_device(dev); | ||
| 924 | while (pd->tx_skb_i != pd->tx_skb_o) | ||
| 925 | dev_kfree_skb(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]); | ||
| 926 | while (pd->rx_skb_i != pd->rx_skb_o) | ||
| 927 | dev_kfree_skb(pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]); | ||
| 928 | spin_unlock_irqrestore(&pd->lock, flags); | ||
| 929 | return 0; | ||
| 930 | } | ||
| 931 | |||
| 932 | static struct net_device_stats *s6gmac_stats(struct net_device *dev) | ||
| 933 | { | ||
| 934 | struct s6gmac *pd = netdev_priv(dev); | ||
| 935 | struct net_device_stats *st = (struct net_device_stats *)&pd->stats; | ||
| 936 | int i; | ||
| 937 | do { | ||
| 938 | unsigned long flags; | ||
| 939 | spin_lock_irqsave(&pd->lock, flags); | ||
| 940 | for (i = 0; i < sizeof(pd->stats) / sizeof(unsigned long); i++) | ||
| 941 | pd->stats[i] = | ||
| 942 | pd->carry[i] << (S6_GMAC_STAT_SIZE_MIN - 1); | ||
| 943 | s6gmac_stats_collect(pd, &statinf[0][0]); | ||
| 944 | s6gmac_stats_collect(pd, &statinf[1][0]); | ||
| 945 | i = s6gmac_stats_pending(pd, 0) | | ||
| 946 | s6gmac_stats_pending(pd, 1); | ||
| 947 | spin_unlock_irqrestore(&pd->lock, flags); | ||
| 948 | } while (i); | ||
| 949 | st->rx_errors = st->rx_crc_errors + | ||
| 950 | st->rx_frame_errors + | ||
| 951 | st->rx_length_errors + | ||
| 952 | st->rx_missed_errors; | ||
| 953 | st->tx_errors += st->tx_aborted_errors; | ||
| 954 | return st; | ||
| 955 | } | ||
| 956 | |||
| 957 | static int __devinit s6gmac_probe(struct platform_device *pdev) | ||
| 958 | { | ||
| 959 | struct net_device *dev; | ||
| 960 | struct s6gmac *pd; | ||
| 961 | int res; | ||
| 962 | unsigned long i; | ||
| 963 | struct mii_bus *mb; | ||
| 964 | dev = alloc_etherdev(sizeof(*pd)); | ||
| 965 | if (!dev) { | ||
| 966 | printk(KERN_ERR DRV_PRMT "etherdev alloc failed, aborting.\n"); | ||
| 967 | return -ENOMEM; | ||
| 968 | } | ||
| 969 | dev->open = s6gmac_open; | ||
| 970 | dev->stop = s6gmac_stop; | ||
| 971 | dev->hard_start_xmit = s6gmac_tx; | ||
| 972 | dev->tx_timeout = s6gmac_tx_timeout; | ||
| 973 | dev->watchdog_timeo = HZ; | ||
| 974 | dev->get_stats = s6gmac_stats; | ||
| 975 | dev->irq = platform_get_irq(pdev, 0); | ||
| 976 | pd = netdev_priv(dev); | ||
| 977 | memset(pd, 0, sizeof(*pd)); | ||
| 978 | spin_lock_init(&pd->lock); | ||
| 979 | pd->reg = platform_get_resource(pdev, IORESOURCE_MEM, 0)->start; | ||
| 980 | i = platform_get_resource(pdev, IORESOURCE_DMA, 0)->start; | ||
| 981 | pd->tx_dma = DMA_MASK_DMAC(i); | ||
| 982 | pd->tx_chan = DMA_INDEX_CHNL(i); | ||
| 983 | i = platform_get_resource(pdev, IORESOURCE_DMA, 1)->start; | ||
| 984 | pd->rx_dma = DMA_MASK_DMAC(i); | ||
| 985 | pd->rx_chan = DMA_INDEX_CHNL(i); | ||
| 986 | pd->io = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; | ||
| 987 | res = request_irq(dev->irq, &s6gmac_interrupt, 0, dev->name, dev); | ||
| 988 | if (res) { | ||
| 989 | printk(KERN_ERR DRV_PRMT "irq request failed: %d\n", dev->irq); | ||
| 990 | goto errirq; | ||
| 991 | } | ||
| 992 | res = register_netdev(dev); | ||
| 993 | if (res) { | ||
| 994 | printk(KERN_ERR DRV_PRMT "error registering device %s\n", | ||
| 995 | dev->name); | ||
| 996 | goto errdev; | ||
| 997 | } | ||
| 998 | mb = mdiobus_alloc(); | ||
| 999 | if (!mb) { | ||
| 1000 | printk(KERN_ERR DRV_PRMT "error allocating mii bus\n"); | ||
| 1001 | goto errmii; | ||
| 1002 | } | ||
| 1003 | mb->name = "s6gmac_mii"; | ||
| 1004 | mb->read = s6mii_read; | ||
| 1005 | mb->write = s6mii_write; | ||
| 1006 | mb->reset = s6mii_reset; | ||
| 1007 | mb->priv = pd; | ||
| 1008 | snprintf(mb->id, MII_BUS_ID_SIZE, "0"); | ||
| 1009 | mb->phy_mask = ~(1 << 0); | ||
| 1010 | mb->irq = &pd->mii.irq[0]; | ||
| 1011 | for (i = 0; i < PHY_MAX_ADDR; i++) { | ||
| 1012 | int n = platform_get_irq(pdev, i + 1); | ||
| 1013 | if (n < 0) | ||
| 1014 | n = PHY_POLL; | ||
| 1015 | pd->mii.irq[i] = n; | ||
| 1016 | } | ||
| 1017 | mdiobus_register(mb); | ||
| 1018 | pd->mii.bus = mb; | ||
| 1019 | res = s6gmac_phy_start(dev); | ||
| 1020 | if (res) | ||
| 1021 | return res; | ||
| 1022 | platform_set_drvdata(pdev, dev); | ||
| 1023 | return 0; | ||
| 1024 | errmii: | ||
| 1025 | unregister_netdev(dev); | ||
| 1026 | errdev: | ||
| 1027 | free_irq(dev->irq, dev); | ||
| 1028 | errirq: | ||
| 1029 | free_netdev(dev); | ||
| 1030 | return res; | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | static int __devexit s6gmac_remove(struct platform_device *pdev) | ||
| 1034 | { | ||
| 1035 | struct net_device *dev = platform_get_drvdata(pdev); | ||
| 1036 | if (dev) { | ||
| 1037 | struct s6gmac *pd = netdev_priv(dev); | ||
| 1038 | mdiobus_unregister(pd->mii.bus); | ||
| 1039 | unregister_netdev(dev); | ||
| 1040 | free_irq(dev->irq, dev); | ||
| 1041 | free_netdev(dev); | ||
| 1042 | platform_set_drvdata(pdev, NULL); | ||
| 1043 | } | ||
| 1044 | return 0; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | static struct platform_driver s6gmac_driver = { | ||
| 1048 | .probe = s6gmac_probe, | ||
| 1049 | .remove = __devexit_p(s6gmac_remove), | ||
| 1050 | .driver = { | ||
| 1051 | .name = "s6gmac", | ||
| 1052 | .owner = THIS_MODULE, | ||
| 1053 | }, | ||
| 1054 | }; | ||
| 1055 | |||
| 1056 | static int __init s6gmac_init(void) | ||
| 1057 | { | ||
| 1058 | printk(KERN_INFO DRV_PRMT "S6 GMAC ethernet driver\n"); | ||
| 1059 | return platform_driver_register(&s6gmac_driver); | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | |||
| 1063 | static void __exit s6gmac_exit(void) | ||
| 1064 | { | ||
| 1065 | platform_driver_unregister(&s6gmac_driver); | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | module_init(s6gmac_init); | ||
| 1069 | module_exit(s6gmac_exit); | ||
| 1070 | |||
| 1071 | MODULE_LICENSE("GPL"); | ||
| 1072 | MODULE_DESCRIPTION("S6105 on chip Ethernet driver"); | ||
| 1073 | MODULE_AUTHOR("Oskar Schirmer <os@emlix.com>"); | ||
