Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62747cd2 authored by Akira Takeuchi's avatar Akira Takeuchi Committed by David Howells
Browse files

MN10300: ASB2364: Add support for SMSC911X and SMC911X



Add support for SMSC911X and SMC911X for the ASB2364 unit.

Signed-off-by: default avatarAkira Takeuchi <takeuchi.akr@jp.panasonic.com>
Signed-off-by: default avatarKiyoshi Owada <owada.kiyoshi@jp.panasonic.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
cc: steve.glendinning@smsc.com
cc: netdev@vger.kernel.org
parent 6044cf1d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ config MN10300_UNIT_ASB2305

config MN10300_UNIT_ASB2364
	bool "ASB2364"
	select SMSC911X_ARCH_HOOKS if SMSC911X

endchoice

+1 −0
Original line number Diff line number Diff line
#include <unit/smsc911x.h>
+2 −0
Original line number Diff line number Diff line
@@ -8,3 +8,5 @@
# Note 2! The CFLAGS definitions are now in the main makefile...

obj-y   := unit-init.o leds.o irq-fpga.o

obj-$(CONFIG_SMSC911X) += smsc911x.o
+171 −0
Original line number Diff line number Diff line
/* Support for the SMSC911x NIC
 *
 * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd.
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */
#ifndef _ASM_UNIT_SMSC911X_H
#define _ASM_UNIT_SMSC911X_H

#include <linux/netdevice.h>
#include <proc/irq.h>
#include <unit/fpga-regs.h>

#define MN10300_USE_EXT_EEPROM


#define SMSC911X_BASE		0xA8000000UL
#define SMSC911X_BASE_END	0xA8000100UL
#define SMSC911X_IRQ		FPGA_LAN_IRQ

/*
 * Allow the FPGA to be initialised by the SMSC911x driver
 */
#undef SMSC_INITIALIZE
#define SMSC_INITIALIZE()					\
do {								\
	/* release reset */					\
	ASB2364_FPGA_REG_RESET_LAN = 0x0001;			\
	SyncExBus();						\
} while (0)

#ifdef MN10300_USE_EXT_EEPROM
#include <linux/delay.h>
#include <unit/clock.h>

#define EEPROM_ADDRESS	0xA0
#define MAC_OFFSET	0x0008
#define USE_IIC_CH	0	/* 0 or 1 */
#define IIC_OFFSET	(0x80000 * USE_IIC_CH)
#define IIC_DTRM	__SYSREG(0xd8400000 + IIC_OFFSET, u32)
#define IIC_DREC	__SYSREG(0xd8400004 + IIC_OFFSET, u32)
#define IIC_MYADD	__SYSREG(0xd8400008 + IIC_OFFSET, u32)
#define IIC_CLK		__SYSREG(0xd840000c + IIC_OFFSET, u32)
#define IIC_BRST	__SYSREG(0xd8400010 + IIC_OFFSET, u32)
#define IIC_HOLD	__SYSREG(0xd8400014 + IIC_OFFSET, u32)
#define IIC_BSTS	__SYSREG(0xd8400018 + IIC_OFFSET, u32)
#define IIC_ICR		__SYSREG(0xd4000080 + 4 * USE_IIC_CH, u16)

#define IIC_CLK_PLS	((unsigned short)(MN10300_IOCLK / 100000 - 1))
#define IIC_CLK_LOW	((unsigned short)(IIC_CLK_PLS / 2))

#define SYS_IIC_DTRM_Bit_STA	((unsigned short)0x0400)
#define SYS_IIC_DTRM_Bit_STO	((unsigned short)0x0200)
#define SYS_IIC_DTRM_Bit_ACK	((unsigned short)0x0100)
#define SYS_IIC_DTRM_Bit_DATA	((unsigned short)0x00FF)

static inline void POLL_INT_REQ(volatile u16 *icr)
{
	unsigned long flags;
	u16 tmp;

	while (!(*icr & GxICR_REQUEST))
		;
	flags = arch_local_cli_save();
	tmp = *icr;
	*icr = (tmp & GxICR_LEVEL) | GxICR_DETECT;
	tmp = *icr;
	arch_local_irq_restore(flags);
}

/*
 * Implement the SMSC911x hook for MAC address retrieval
 */
#undef smsc_get_mac
static inline int smsc_get_mac(struct net_device *dev)
{
	unsigned char *mac_buf = dev->dev_addr;
	int i;
	unsigned short value;
	unsigned int data;
	int mac_length = 6;
	int check;
	u16 orig_gicr, tmp;
	unsigned long flags;

	/* save original GnICR and clear GnICR.IE */
	flags = arch_local_cli_save();
	orig_gicr = IIC_ICR;
	IIC_ICR = orig_gicr & GxICR_LEVEL;
	tmp = IIC_ICR;
	arch_local_irq_restore(flags);

	IIC_MYADD = 0x00000008;
	IIC_CLK = (IIC_CLK_LOW << 16) + (IIC_CLK_PLS);
	/* bus hung recovery */

	while (1) {
		check = 0;
		for (i = 0; i < 3; i++) {
			if ((IIC_BSTS & 0x00000003) == 0x00000003)
				check++;
			udelay(3);
		}

		if (check == 3) {
			IIC_BRST = 0x00000003;
			break;
		} else {
			for (i = 0; i < 3; i++) {
				IIC_BRST = 0x00000002;
				udelay(8);
				IIC_BRST = 0x00000003;
				udelay(8);
			}
		}
	}

	IIC_BRST = 0x00000002;
	IIC_BRST = 0x00000003;

	value	=  SYS_IIC_DTRM_Bit_STA | SYS_IIC_DTRM_Bit_ACK;
	value	|= (((unsigned short)EEPROM_ADDRESS & SYS_IIC_DTRM_Bit_DATA) |
		    (unsigned short)0x0000);
	IIC_DTRM = value;
	POLL_INT_REQ(&IIC_ICR);

	/** send offset of MAC address in EEPROM **/
	IIC_DTRM = (unsigned char)((MAC_OFFSET & 0xFF00) >> 8);
	POLL_INT_REQ(&IIC_ICR);

	IIC_DTRM = (unsigned char)(MAC_OFFSET & 0x00FF);
	POLL_INT_REQ(&IIC_ICR);

	udelay(1000);

	value	=  SYS_IIC_DTRM_Bit_STA;
	value	|= (((unsigned short)EEPROM_ADDRESS & SYS_IIC_DTRM_Bit_DATA) |
		    (unsigned short)0x0001);
	IIC_DTRM = value;
	POLL_INT_REQ(&IIC_ICR);

	IIC_DTRM = 0x00000000;
	while (mac_length > 0) {
		POLL_INT_REQ(&IIC_ICR);

		data = IIC_DREC;
		mac_length--;
		if (mac_length == 0)
			value = 0x00000300;	/* stop IIC bus */
		else if (mac_length == 1)
			value = 0x00000100;	/* no ack */
		else
			value = 0x00000000;	/* ack */
		IIC_DTRM = value;
		*mac_buf++ = (unsigned char)(data & 0xff);
	}

	/* restore GnICR.LV and GnICR.IE */
	flags = arch_local_cli_save();
	IIC_ICR = (orig_gicr & (GxICR_LEVEL | GxICR_ENABLE));
	tmp = IIC_ICR;
	arch_local_irq_restore(flags);

	return 0;
}
#endif /* MN10300_USE_EXT_EEPROM */
#endif /* _ASM_UNIT_SMSC911X_H */
+58 −0
Original line number Diff line number Diff line
/* Specification for the SMSC911x NIC
 *
 * Copyright (C) 2006 Matsushita Electric Industrial Co., Ltd.
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/smsc911x.h>
#include <unit/smsc911x.h>

static struct smsc911x_platform_config smsc911x_config = {
	.irq_polarity	= SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
	.irq_type	= SMSC911X_IRQ_TYPE_OPEN_DRAIN,
	.flags		= SMSC911X_USE_32BIT,
};

static struct resource smsc911x_resources[] = {
	[0] = {
		.start	= SMSC911X_BASE,
		.end	= SMSC911X_BASE_END,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= SMSC911X_IRQ,
		.end	= SMSC911X_IRQ,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device smsc911x_device = {
	.name		= "smsc911x",
	.id		= 0,
	.num_resources	= ARRAY_SIZE(smsc911x_resources),
	.resource	= smsc911x_resources,
	.dev		= {
		.platform_data = &smsc911x_config,
	}
};

/*
 * add platform devices
 */
static int __init unit_device_init(void)
{
	platform_device_register(&smsc911x_device);
	return 0;
}

device_initcall(unit_device_init);
Loading