Merge branch 'mindspeed_drops' into master
Change-Id: Iace5a5c61f7b46f709904691be44fdda4a132b0b
diff --git a/arch/arm/configs/gfrg200_defconfig b/arch/arm/configs/gfrg200_defconfig
new file mode 100644
index 0000000..5bde767
--- /dev/null
+++ b/arch/arm/configs/gfrg200_defconfig
@@ -0,0 +1,299 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+# CONFIG_NET_NS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PRINTK_PERSIST=y
+CONFIG_BOOTLOG_COPY=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_COMCERTO=y
+CONFIG_GOOGLE_FIBER_OPTIMUS=y
+CONFIG_COMCERTO_MEMBUF=y
+CONFIG_COMCERTO_EPAVIS=y
+# CONFIG_COMCERTO_MSP is not set
+CONFIG_COMCERTO_SATA=y
+CONFIG_COMCERTO_ZONE_DMA_NCNB=y
+CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT=y
+CONFIG_DSPG_DECT_CSS=y
+# CONFIG_SWP_EMULATE is not set
+CONFIG_PCI=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_VMSPLIT_2G=y
+CONFIG_NR_CPUS=2
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_ZBOOT_ROM_TEXT=0x3008000
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_MROUTE=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_IPV6_SIT is not set
+CONFIG_NETFILTER=y
+# CONFIG_BRIDGE_NETFILTER is not set
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_LAYER7=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NF_CONNTRACK_IPV4=m
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_RAW=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+CONFIG_NET_SCHED=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WEXT_SPY=y
+CONFIG_WEXT_PRIV=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC_BCH=y
+CONFIG_MTD_NAND_COMCERTO=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=128
+CONFIG_MTD_UBI_BEB_RESERVE=25
+CONFIG_MTD_UBI_GLUEBI=y
+CONFIG_MISC_DEVICES=y
+CONFIG_EEPROM_AT24=y
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SATA_PMP is not set
+CONFIG_SATA_AHCI=y
+# CONFIG_ATA_SFF is not set
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_TUN=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_HP is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+CONFIG_PHYLIB=y
+CONFIG_ATHEROS_PHY=y
+CONFIG_FIXED_PHY=y
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=32
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_I2C_SMBUS=y
+CONFIG_I2C_COMCERTO=y
+CONFIG_SPI=y
+CONFIG_SPI_DEBUG=y
+CONFIG_HWMON_DEBUG_CHIP=y
+CONFIG_SENSORS_LM63=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_COMCERTO_WATCHDOG=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+# CONFIG_RTC_INTF_SYSFS is not set
+# CONFIG_RTC_INTF_PROC is not set
+# CONFIG_RTC_INTF_DEV is not set
+CONFIG_EXT4_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_DEBUG=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_EMBEDDED=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_ARM_UNWIND is not set
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_CCITT=m
+CONFIG_AVERAGE=y
diff --git a/arch/arm/mach-comcerto/Kconfig b/arch/arm/mach-comcerto/Kconfig
index 3735479..f94f77c 100644
--- a/arch/arm/mach-comcerto/Kconfig
+++ b/arch/arm/mach-comcerto/Kconfig
@@ -46,6 +46,12 @@
prompt "Comcerto Board type"
default RTSM_C2K
+config GOOGLE_FIBER_OPTIMUS
+ bool "Google Fiber Optimus"
+ depends on ARCH_M86XXX
+ help
+ Say Y here if you intend to run this kernel with a Google Fiber Optimus board.
+
config C2K_EVM
bool "EVM"
depends on ARCH_M86XXX
diff --git a/arch/arm/mach-comcerto/Makefile b/arch/arm/mach-comcerto/Makefile
index 9f5cfa0..9cc213a 100644
--- a/arch/arm/mach-comcerto/Makefile
+++ b/arch/arm/mach-comcerto/Makefile
@@ -21,6 +21,7 @@
obj-$(CONFIG_COMCERTO_MEMBUF) += membuf.o
obj-$(CONFIG_COMCERTO_TDM_CLOCK) += sysfstdm.o
obj-$(CONFIG_RTSM_C2K) += board-c2krtsm.o
+obj-$(CONFIG_GOOGLE_FIBER_OPTIMUS) += board-optimus.o
obj-$(CONFIG_C2K_EVM) += board-c2kevm.o
obj-$(CONFIG_C2K_MFCN_EVM) += board-c2kmfcnevm.o
obj-$(CONFIG_C2K_ASIC) += board-c2kasic.o
@@ -28,3 +29,4 @@
obj-$(CONFIG_COMCERTO_MSP) += msp/
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_COMCERTO_CSYS_TPI_CLOCK) += comcerto-tpicsys.o
+obj-$(CONFIG_BOOTLOG_COPY) += bootlog.o
diff --git a/arch/arm/mach-comcerto/board-c2kevm.c b/arch/arm/mach-comcerto/board-c2kevm.c
index d944636..a99dab7 100644
--- a/arch/arm/mach-comcerto/board-c2kevm.c
+++ b/arch/arm/mach-comcerto/board-c2kevm.c
@@ -587,7 +587,7 @@
static struct comcerto_pfe_platform_data comcerto_pfe_pdata = {
.comcerto_eth_pdata[0] = {
- .name = GEM0_ITF_NAME,
+ .name = "wan0",
.device_flags = CONFIG_COMCERTO_GEMAC,
.mii_config = CONFIG_COMCERTO_USE_RGMII,
.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
@@ -599,7 +599,7 @@
},
.comcerto_eth_pdata[1] = {
- .name = GEM1_ITF_NAME,
+ .name = "lan0",
.device_flags = CONFIG_COMCERTO_GEMAC,
.mii_config = CONFIG_COMCERTO_USE_RGMII,
.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
@@ -609,7 +609,7 @@
},
.comcerto_eth_pdata[2] = {
- .name = GEM2_ITF_NAME,
+ .name = "moca0",
.device_flags = CONFIG_COMCERTO_GEMAC,
.mii_config = CONFIG_COMCERTO_USE_RGMII,
.gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
diff --git a/arch/arm/mach-comcerto/board-optimus.c b/arch/arm/mach-comcerto/board-optimus.c
new file mode 100644
index 0000000..682e9b0
--- /dev/null
+++ b/arch/arm/mach-comcerto/board-optimus.c
@@ -0,0 +1,693 @@
+/*
+ * arch/arm/mach-comcerto/board-optimus.c
+ *
+ * Copyright (C) 2012 Mindspeed Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/sched.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <linux/memblock.h>
+#include <linux/phy.h>
+
+#include <linux/mtd/mtd.h>
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+#include <linux/mtd/nand.h>
+#endif
+#include <linux/mtd/partitions.h>
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+#include <linux/spi/spi.h>
+#endif
+
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+#include <linux/i2c.h>
+#endif
+
+#include <asm/sizes.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+
+#include <asm/mach/flash.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/dma.h>
+#include <linux/dw_dmac.h>
+
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/smp_twd.h>
+#include <asm/localtimer.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/time.h>
+#include <mach/gpio.h>
+
+
+extern void platform_reserve(void);
+extern void device_map_io (void);
+extern void device_irq_init(void);
+extern void device_init(void);
+extern void mac_addr_init(struct comcerto_pfe_platform_data *);
+extern struct sys_timer comcerto_timer;
+
+static void __init board_gpio_init(void)
+{
+#ifdef CONFIG_COMCERTO_PFE_UART_SUPPORT
+ writel((readl(COMCERTO_GPIO_PIN_SELECT_REG) & ~PFE_UART_GPIO) | PFE_UART_BUS, COMCERTO_GPIO_PIN_SELECT_REG);
+ c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= PFE_UART_GPIO_PIN; /* GPIOs 12 & 13 are used for PFE_UART */
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+ /* enable SPI pins */
+ writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_MUX_GPIO_1)) | (SPI_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+ writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_MUX_GPIO_2)) | (SPI_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+ c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= SPI_MUX_GPIO_1_PIN; /* GPIOs 18,19, 21,22, 30,31 are used for SPI*/
+ c2k_gpio_pin_stat.c2k_gpio_pins_32_63 |= SPI_MUX_GPIO_2_PIN; /* GPIO 32 is used for SPI*/
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+ /* enable SPI pins */
+ writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~(SPI_2_MUX_GPIO_1)) | (SPI_2_MUX_BUS_1), COMCERTO_GPIO_PIN_SELECT_REG1);
+ writel((readl(COMCERTO_GPIO_63_32_PIN_SELECT) & ~(SPI_2_MUX_GPIO_2)) | (SPI_2_MUX_BUS_2), COMCERTO_GPIO_63_32_PIN_SELECT);
+ c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= SPI_2_MUX_GPIO_1_PIN;
+ c2k_gpio_pin_stat.c2k_gpio_pins_32_63 |= SPI_2_MUX_GPIO_2_PIN;
+#endif
+
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+ writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~I2C_GPIO) | I2C_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+ c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= I2C_GPIO_PIN;
+#endif
+
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+ writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NAND_GPIO) | NAND_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+ c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= NAND_GPIO_PIN;
+#endif
+
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+ writel((readl(COMCERTO_GPIO_PIN_SELECT_REG1) & ~NOR_GPIO) | NOR_BUS, COMCERTO_GPIO_PIN_SELECT_REG1);
+ c2k_gpio_pin_stat.c2k_gpio_pins_0_31 |= NOR_GPIO_PIN;
+#endif
+
+#ifdef MOCA_RESET_GPIO_PIN
+ __raw_writel(__raw_readl(COMCERTO_GPIO_OUTPUT_REG) | MOCA_RESET_GPIO_PIN, COMCERTO_GPIO_OUTPUT_REG);
+#endif
+
+ // enable GPIO0 interrupt (for MoCA) as level triggered, active high.
+ __raw_writel(__raw_readl(COMCERTO_GPIO_INT_CFG_REG) | (0x3),
+ COMCERTO_GPIO_INT_CFG_REG);
+}
+
+/* --------------------------------------------------------------------
+ * NOR device
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+
+static struct resource comcerto_nor_resources[] = {
+ {
+ .start = NORFLASH_MEMORY_PHY1,
+ .end = NORFLASH_MEMORY_PHY1 + SZ_64M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct flash_platform_data comcerto_nor_data = {
+ .map_name = "cfi_probe",
+ .width = 2,
+};
+
+static struct platform_device comcerto_nor = {
+ .name = "comcertoflash",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(comcerto_nor_resources),
+ .resource = comcerto_nor_resources,
+ .dev = {
+ .platform_data = &comcerto_nor_data,
+ },
+};
+#endif
+
+static struct resource rtc_res[] = {
+ {
+ .start = COMCERTO_APB_RTC_BASE,
+ .end = COMCERTO_APB_RTC_BASE + SZ_32 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_RTC_ALM,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = IRQ_RTC_PRI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+static struct platform_device rtc_dev = {
+ .name = "c2k-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_res),
+ .resource = rtc_res,
+};
+
+/* --------------------------------------------------------------------
+ * DMAC controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+static struct resource dw_dmac_resource[] = {
+ {
+ .start = DW_DMA_DMAC_BASEADDR,
+ .end = DW_DMA_DMAC_BASEADDR + 0x2C0,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_DMAC,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct dw_dma_platform_data dw_dmac_data = {
+ .nr_channels = 8,
+};
+
+static u64 dw_dmac_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device dw_dmac_device = {
+ .name = "dw_dmac",
+ .id = 0,
+ .dev = {
+ .dma_mask = &dw_dmac_dma_mask,
+ .platform_data = &dw_dmac_data,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .resource = dw_dmac_resource,
+ .num_resources = ARRAY_SIZE(dw_dmac_resource),
+};
+#endif
+
+/* --------------------------------------------------------------------
+ * NAND device
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+static struct resource comcerto_nand_resources[] = {
+ {
+ .start = COMCERTO_NAND_FIO_ADDR,
+ .end = COMCERTO_NAND_FIO_ADDR + COMCERTO_NAND_IO_SZ - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device comcerto_nand = {
+ .name = "comcertonand",
+ .id = -1,
+ .dev = {
+ .platform_data = NULL,
+ },
+ .resource = comcerto_nand_resources,
+ .num_resources = ARRAY_SIZE(comcerto_nand_resources),
+};
+#endif
+
+/* --------------------------------------------------------------------
+ * SPI bus controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+
+#define CLK_NAME 10
+struct spi_controller_pdata {
+ int use_dma;
+ int num_chipselects;
+ int bus_num;
+ u32 max_freq;
+ char clk_name[CLK_NAME];
+};
+
+struct spi_platform_data {
+ int type;
+ int dummy;
+};
+
+struct spi_controller_data {
+ u8 poll_mode; /* 0 for contoller polling mode */
+ u8 type; /* SPI/SSP/Micrwire */
+ u8 enable_dma;
+ void (*cs_control)(u32 command);
+};
+
+struct spi_platform_data spi_pdata = {
+ .type = 0,
+ .dummy = 0,
+};
+
+struct spi_controller_data spi_ctrl_data = {
+ .poll_mode = 1,
+};
+
+// We list more than one bmoca in here because it was attached to different
+// chip selects in different variations of the board. We have to trust the
+// driver to reject instances that aren't actually present.
+static struct spi_board_info comcerto_spi_board_info[] = {
+ {
+ .modalias = "bmoca",
+ .chip_select = 0,
+ .max_speed_hz = 20*1000*1000,
+ .bus_num = 0,
+ .irq = IRQ_G0,
+ .mode = SPI_MODE_3,
+ .platform_data = &spi_pdata,
+ .controller_data = &spi_ctrl_data,
+ },
+
+ {
+ .modalias = "bmoca",
+ .chip_select = 0,
+ .max_speed_hz = 20*1000*1000,
+ .bus_num = 1,
+ .irq = IRQ_G0,
+ .mode = SPI_MODE_3,
+ .platform_data = &spi_pdata,
+ .controller_data = &spi_ctrl_data,
+ },
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+struct spi_controller_pdata fast_spi_pdata = {
+ .use_dma = 0,
+ .num_chipselects = 2,
+ .bus_num = 1,
+ .max_freq = 50 * 1000 * 1000,
+ .clk_name = "DUS",
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI2_MSPD_HIGH_SPEED)
+static struct resource comcerto_fast_spi_resource[] = {
+ {
+ .start = COMCERTO_AXI_SPI_BASE,
+ .end = COMCERTO_AXI_SPI_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_SPI,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device comcerto_fast_spi = {
+ .name = "comcerto_spi",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(comcerto_fast_spi_resource),
+ .resource = comcerto_fast_spi_resource,
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+ .dev = {
+ .platform_data = &fast_spi_pdata,
+ },
+#endif
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+struct spi_controller_pdata ls_spi_pdata = {
+ .use_dma = 0,
+ .num_chipselects = 4,
+ .bus_num = 0,
+ .max_freq = 20 * 1000 * 1000,
+ .clk_name = "spi_i2c",
+};
+#endif
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+static struct resource comcerto_spi_resource[] = {
+ {
+ .start = COMCERTO_APB_SPI_BASE,
+ .end = COMCERTO_APB_SPI_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_SPI_LS,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device comcerto_spi = {
+ .name = "comcerto_spi",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(comcerto_spi_resource),
+ .resource = comcerto_spi_resource,
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED)
+ .dev = {
+ .platform_data = &ls_spi_pdata,
+ },
+#endif
+};
+#endif
+
+/* --------------------------------------------------------------------
+ * I2C bus controller
+ * -------------------------------------------------------------------- */
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+static struct resource comcerto_i2c_resources[] = {
+ {
+ .start = COMCERTO_APB_I2C_BASE,
+ .end = COMCERTO_APB_I2C_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct i2c_board_info comcerto_i2c_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("lm96163", 0x4c),
+ },
+ {
+ I2C_BOARD_INFO("24c512", 0x50),
+ },
+};
+
+static struct platform_device comcerto_i2c = {
+ .name = "comcerto_i2c",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(comcerto_i2c_resources),
+ .resource = comcerto_i2c_resources,
+};
+#endif
+
+/* --------------------------------------------------------------------
+* Watchdog
+* -------------------------------------------------------------------- */
+#ifdef CONFIG_MPCORE_WATCHDOG
+static struct resource comcerto_a9wd_resources[] = {
+ {
+ .start = COMCERTO_TWD_BASE,
+ .end = COMCERTO_TWD_BASE + 0xFF,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mpcore_wdt",
+ .start = IRQ_LOCALWDOG,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device comcerto_a9wd = {
+ .name = "mpcore_wdt",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(comcerto_a9wd_resources),
+ .resource = comcerto_a9wd_resources,
+};
+#endif
+
+#ifdef CONFIG_COMCERTO_WATCHDOG
+static struct resource comcerto_wdt_resources[] = {
+ {
+ .start = COMCERTO_APB_TIMER_BASE + 0xD0,
+ .end = COMCERTO_APB_TIMER_BASE + 0xD8,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device comcerto_wdt = {
+ .name = "comcerto_wdt",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(comcerto_wdt_resources),
+ .resource = comcerto_wdt_resources,
+};
+#endif
+
+#if defined(CONFIG_COMCERTO_ELP_SUPPORT)
+/* --------------------------------------------------------------------
+ * IPsec
+ * -------------------------------------------------------------------- */
+static struct resource comcerto_elp_resources[] = {
+ {
+ .name = "elp",
+ .start = COMCERTO_AXI_SPACC_PDU_BASE,
+ .end = COMCERTO_AXI_SPACC_PDU_BASE + SZ_16M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "irq_spacc",
+ .start = IRQ_SPACC,
+ .end = IRQ_SPACC,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 comcerto_elp_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device comcerto_elp_device = {
+ .name = "Elliptic-EPN1802",
+ .id = 0,
+ .num_resources = 2,
+ .resource = comcerto_elp_resources,
+ .dev = {
+ .dma_mask = &comcerto_elp_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+#endif
+
+static struct comcerto_tdm_data comcerto_tdm_pdata = {
+ .fsoutput = 1, /* Generic Pad Control and Version ID Register[2] */
+ .fspolarity = 0, /* 28 FSYNC_FALL(RISE)_EDGE */
+ .fshwidth = 1, /* High_Phase_Width[10:0] */
+ .fslwidth = 0xFF, /* Low_Phase_Width[10:0] */
+ .clockhz = 2048000, /* INC_VALUE[29:0] According to the desired TDM clock output frequency, this field should be configured */
+ .clockout = 1, /* 0 -> set bit 21, clear bit 20 in COMCERTO_GPIO_IOCTRL_REG
+ (software control, clock input)
+ 1 -> set bit 21 and 20 in COMCERTO_GPIO_IOCTRL_REG
+ (software control, clock output)
+ 2 -> clear bit 21 in COMCERTO_GPIO_IOCTRL_REG (hardware control) */
+ .tdmmux = 0x1, /* TDM interface Muxing:0x0 - TDM block, 0x1 - ZDS block,
+ 0x2 - GPIO[63:60] signals and 0x3 - MSIF block is selected */
+#if 0
+ /* FIX ME - Need correct values for TDM_DR, TDM_DX, TDM_FS and TDM_CK */
+ .tdmck = 0x3F,
+ .tdmfs = 0x3F,
+ .tdmdx = 0x3F,
+ .tdmdr = 0x3F,
+#endif
+};
+
+static struct platform_device comcerto_tdm_device = {
+ .name = "comcerto-tdm",
+ .id = 0,
+ .dev.platform_data = &comcerto_tdm_pdata,
+ .num_resources = 0,
+ .resource = NULL,
+};
+
+static struct resource comcerto_pfe_resources[] = {
+ {
+ .name = "apb",
+ .start = COMCERTO_APB_PFE_BASE,
+ .end = COMCERTO_APB_PFE_BASE + COMCERTO_APB_PFE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "axi",
+ .start = COMCERTO_AXI_PFE_BASE,
+ .end = COMCERTO_AXI_PFE_BASE + COMCERTO_AXI_PFE_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ddr",
+ .start = COMCERTO_PFE_DDR_BASE,
+ .end = COMCERTO_PFE_DDR_BASE + COMCERTO_PFE_DDR_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "iram",
+ .start = COMCERTO_PFE_IRAM_BASE,
+ .end = COMCERTO_PFE_IRAM_BASE + COMCERTO_PFE_IRAM_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ipsec",
+ .start = COMCERTO_AXI_IPSEC_BASE,
+ .end = COMCERTO_AXI_IPSEC_BASE + COMCERTO_AXI_IPSEC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+
+ {
+ .name = "hif",
+ .start = IRQ_PFE_HIF,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct comcerto_pfe_platform_data comcerto_pfe_pdata = {
+ .comcerto_eth_pdata[0] = {
+ .name = "lan0",
+ .device_flags = CONFIG_COMCERTO_GEMAC,
+ .mii_config = CONFIG_COMCERTO_USE_RGMII,
+ .gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+ .phy_flags = GEMAC_NO_PHY,
+ .gem_id = 0,
+ .mac_addr = (u8[])GEM0_MAC,
+ },
+
+ .comcerto_eth_pdata[1] = {
+ .name = "wan0",
+ .device_flags = CONFIG_COMCERTO_GEMAC,
+ .mii_config = CONFIG_COMCERTO_USE_RGMII,
+ .gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+ .phy_flags = GEMAC_PHY_RGMII_ADD_DELAY,
+ .bus_id = 0,
+ .phy_id = 4,
+ .gem_id = 1,
+ .mac_addr = (u8[])GEM1_MAC,
+ },
+
+ .comcerto_eth_pdata[2] = {
+ .name = "moca0",
+ .device_flags = CONFIG_COMCERTO_GEMAC,
+ .mii_config = CONFIG_COMCERTO_USE_RGMII,
+ .gemac_mode = GEMAC_SW_CONF | GEMAC_SW_FULL_DUPLEX | GEMAC_SW_SPEED_1G,
+ .phy_flags = GEMAC_NO_PHY,
+ .gem_id = 2,
+ .mac_addr = (u8[])GEM2_MAC,
+ },
+
+ /**
+ * There is a single mdio bus coming out of C2K. And that's the one
+ * connected to GEM0. All PHY's, switchs will be connected to the same
+ * bus using different addresses. Typically .bus_id is always 0, only
+ * .phy_id will change in the different comcerto_eth_pdata[] structures above.
+ */
+ .comcerto_mdio_pdata[0] = {
+ .enabled = 1,
+ .phy_mask = 0xFFFFFFEF,
+ .mdc_div = 96,
+ .irq = {
+ [4] = PHY_POLL,
+ },
+ },
+};
+
+static u64 comcerto_pfe_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device comcerto_pfe_device = {
+ .name = "pfe",
+ .id = 0,
+ .dev = {
+ .platform_data = &comcerto_pfe_pdata,
+ .dma_mask = &comcerto_pfe_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+ .num_resources = ARRAY_SIZE(comcerto_pfe_resources),
+ .resource = comcerto_pfe_resources,
+};
+
+static struct platform_device *comcerto_devices[] __initdata = {
+#if defined(CONFIG_MTD_NAND_COMCERTO) || defined(CONFIG_MTD_NAND_COMCERTO_MODULE)
+ &comcerto_nand,
+#endif
+#if defined(CONFIG_MTD_COMCERTO_NOR)
+ &comcerto_nor,
+#endif
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+ &comcerto_i2c,
+#endif
+
+#if defined (CONFIG_MPCORE_WATCHDOG)
+ &comcerto_a9wd,
+#endif
+
+#if defined(CONFIG_COMCERTO_WATCHDOG)
+ &comcerto_wdt,
+#endif
+
+#if defined(CONFIG_SPI_MSPD_HIGH_SPEED) || defined(CONFIG_SPI2_MSPD_HIGH_SPEED)
+ &comcerto_fast_spi,
+#endif
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI2_MSPD_LOW_SPEED)
+ &comcerto_spi,
+#endif
+#if defined(CONFIG_COMCERTO_DW_DMA_SUPPORT)
+ &dw_dmac_device,
+#endif
+ &comcerto_tdm_device,
+ &comcerto_pfe_device,
+ &rtc_dev,
+#if defined(CONFIG_COMCERTO_ELP_SUPPORT)
+ &comcerto_elp_device,
+#endif
+};
+
+
+/************************************************************************
+ * Expansion bus
+ *
+ ************************************************************************/
+/* This variable is used by comcerto-2000.c to initialize the expansion bus */
+int comcerto_exp_values[5][7]= {
+ /* ENABLE, BASE, SEG_SZ, CFG, TMG1, TMG2, TMG3 */
+ {1, (EXP_BUS_REG_BASE_CS0 >> 12), ((EXP_BUS_REG_BASE_CS0 + EXP_CS0_SEG_SIZE - 1) >> 12), EXP_MEM_BUS_SIZE_16, 0x1A1A401F, 0x06060A04, 0x00000002}, /*TODO Values to check*/
+ {0, (EXP_BUS_REG_BASE_CS1 >> 12), ((EXP_BUS_REG_BASE_CS1 + EXP_CS1_SEG_SIZE - 1) >> 12), EXP_RDY_EN|EXP_MEM_BUS_SIZE_32, 0x1A1A401F, 0x06060A04, 0x00000002}, /*TODO Values to check*/
+ {0, (EXP_BUS_REG_BASE_CS2 >> 12), ((EXP_BUS_REG_BASE_CS2 + EXP_CS2_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002}, /*TODO Values to check*/
+ {0, (EXP_BUS_REG_BASE_CS3 >> 12), ((EXP_BUS_REG_BASE_CS3 + EXP_CS3_SEG_SIZE - 1) >> 12), EXP_STRB_MODE|EXP_ALE_MODE|EXP_MEM_BUS_SIZE_8, 0x1A10201A, 0x03080403, 0x0000002}, /*BT8370*/
+ {0, (EXP_BUS_REG_BASE_CS4 >> 12), ((EXP_BUS_REG_BASE_CS4 + EXP_CS4_SEG_SIZE - 1) >> 12), EXP_NAND_MODE|EXP_MEM_BUS_SIZE_8, 0x01010001, 0x01010101, 0x00000001}, /* NAND: TODO Values to check */
+};
+
+/************************************************************************
+ * Machine definition
+ *
+ ************************************************************************/
+static void __init platform_map_io(void)
+{
+ device_map_io();
+}
+
+static void __init platform_irq_init(void)
+{
+ device_irq_init();
+}
+
+static void __init platform_init(void)
+{
+ device_init();
+ board_gpio_init();
+
+#if defined(CONFIG_SPI_MSPD_LOW_SPEED) || defined(CONFIG_SPI_MSPD_HIGH_SPEED)
+ spi_register_board_info(comcerto_spi_board_info, ARRAY_SIZE(comcerto_spi_board_info));
+#endif
+#if defined(CONFIG_COMCERTO_I2C_SUPPORT)
+ i2c_register_board_info(0, comcerto_i2c_board_info, ARRAY_SIZE(comcerto_i2c_board_info));
+#endif
+ mac_addr_init(&comcerto_pfe_pdata);
+
+ platform_add_devices(comcerto_devices, ARRAY_SIZE(comcerto_devices));
+}
+
+MACHINE_START(COMCERTO, "Google Fiber Optimus")
+ .atag_offset = COMCERTO_AXI_DDR_BASE + 0x100,
+ .reserve = platform_reserve,
+ .map_io = platform_map_io,
+ .init_irq = platform_irq_init,
+ .init_machine = platform_init,
+ .timer = &comcerto_timer,
+#ifdef CONFIG_ZONE_DMA
+ .dma_zone_size = SZ_32M + 3*SZ_4M,
+#endif
+MACHINE_END
diff --git a/arch/arm/mach-comcerto/bootlog.c b/arch/arm/mach-comcerto/bootlog.c
new file mode 100644
index 0000000..357f8ff
--- /dev/null
+++ b/arch/arm/mach-comcerto/bootlog.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* CONFIG_BOOTLOG_COPY */
+
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <linux/compiler.h>
+#include <linux/module.h>
+
+#define BOOTLOG_MAXSIZE (1024*1024)
+
+static unsigned long bootlog_addr = 0;
+static unsigned long bootlog_size = 0;
+static int bootlog_is_reserved = 0;
+
+unsigned long bootlog_get_addr(void)
+{
+
+ if (!bootlog_addr)
+ return 0;
+
+ if (!bootlog_is_reserved) {
+ if (reserve_bootmem(bootlog_addr, bootlog_size, BOOTMEM_EXCLUSIVE)) {
+ printk(KERN_WARNING "bootlog: reserve_bootmem(0x%lx, 0x%lx) failed\n", bootlog_addr, bootlog_size);
+ return 0;
+ }
+ }
+ return bootlog_addr;
+}
+
+unsigned long bootlog_get_size(void)
+{
+ if (!bootlog_addr)
+ return 0;
+
+ return bootlog_size;
+}
+
+void bootlog_free(void)
+{
+ if (bootlog_is_reserved) {
+ free_bootmem(bootlog_addr, bootlog_size);
+ }
+ bootlog_addr = bootlog_size = 0;
+}
+
+static int __init bootlog_setup(char *str)
+{
+ unsigned long addr = 0;
+ unsigned long size;
+
+ size = (unsigned long) memparse(str, &str);
+ if (*str == '@')
+ addr = (unsigned long)memparse(str + 1, &str);
+
+ if (!addr) {
+ printk(KERN_WARNING "bootlog: address and size must not be 0,"
+ " ignoring range '%s'\n", str);
+ return 0;
+ }
+
+ bootlog_addr = addr;
+ bootlog_size = size;
+
+ return 0;
+}
+
+early_param("bootlog", bootlog_setup);
diff --git a/arch/arm/mach-comcerto/comcerto-2000.c b/arch/arm/mach-comcerto/comcerto-2000.c
index b5b0cb7..9ce93ed 100644
--- a/arch/arm/mach-comcerto/comcerto-2000.c
+++ b/arch/arm/mach-comcerto/comcerto-2000.c
@@ -207,20 +207,11 @@
/*[FIXME]: GPIO Output, others are input*/
__raw_writel(__raw_readl(COMCERTO_GPIO_OE_REG) | COMCERTO_OUTPUT_GPIO, COMCERTO_GPIO_OE_REG);
- /*[FIXME]: GPIO IRQ Configuration */
- __raw_writel(COMCERTO_IRQ_RISING_EDGE_GPIO, COMCERTO_GPIO_INT_CFG_REG);
-
-#if !defined(CONFIG_C2K_MFCN_EVM)
- /* [FIXME]: Need to have proper defines for enabling the GPIO irq */
- __raw_writel(__raw_readl(COMCERTO_GPIO_OE_REG) | (0x1 << 5), COMCERTO_GPIO_OE_REG); // enable GPIO5 (SLIC_RESET_n) as output
- __raw_writel(__raw_readl(COMCERTO_GPIO_OUTPUT_REG) | (0x1 << 5), COMCERTO_GPIO_OUTPUT_REG); // clear reset
- udelay(15);
- __raw_writel(__raw_readl(COMCERTO_GPIO_OUTPUT_REG) & ~(0x1 << 5), COMCERTO_GPIO_OUTPUT_REG); // put in reset
- udelay(15);
- __raw_writel(__raw_readl(COMCERTO_GPIO_OUTPUT_REG) | (0x1 << 5), COMCERTO_GPIO_OUTPUT_REG); // clear reset after some time
-#endif
- __raw_writel(0x4, COMCERTO_GPIO_INT_CFG_REG); /* si3227 is falling edge interrupt(gpio1) */
-
+ /*
+ * Default GPIO IRQ Configuration. Enable specific IRQs in the
+ * board-*.c file
+ */
+ __raw_writel(0, COMCERTO_GPIO_INT_CFG_REG);
/* [FIXME]: Are pins GPIO or pins used by another block*/
//__raw_writel(COMCERTO_GPIO_PIN_USAGE, COMCERTO_GPIO_IOCTRL_REG);
@@ -284,7 +275,6 @@
__raw_writel(comcerto_exp_values[cs][2], COMCERTO_EXP_CSx_SEG_R(cs));
/*Chip select timing configuration*/
- /* [FIXME] : Using default timing values */
__raw_writel(comcerto_exp_values[cs][4], COMCERTO_EXP_CSx_TMG1_R(cs));
__raw_writel(comcerto_exp_values[cs][5], COMCERTO_EXP_CSx_TMG2_R(cs));
__raw_writel(comcerto_exp_values[cs][6], COMCERTO_EXP_CSx_TMG3_R(cs));
diff --git a/arch/arm/mach-comcerto/include/mach/board-optimus.h b/arch/arm/mach-comcerto/include/mach/board-optimus.h
new file mode 100644
index 0000000..581114c
--- /dev/null
+++ b/arch/arm/mach-comcerto/include/mach/board-optimus.h
@@ -0,0 +1,52 @@
+/*
+ * arch/arm/mach-comcerto/include/mach/board-optimus.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __BOARD_OPTIMUS_H__
+#define __BOARD_OPTIMUS_H__
+
+#include <mach/hardware.h>
+
+ /***********************************
+ * Expansion bus configuration
+ ***********************************/
+
+ #define COMCERTO_EXPCLK 50000000 /* 50MHz */
+ #define MOCA_RESET_GPIO_PIN GPIO_PIN_11
+
+ /***********************************
+ * GPIO
+ ***********************************/
+ #define COMCERTO_OUTPUT_GPIO (COMCERTO_NAND_CE|MOCA_RESET_GPIO_PIN)
+ /*Are pins used either as GPIO or as pins for others IP blocks*/
+ #define COMCERTO_GPIO_PIN_USAGE (SPI_BUS) // [FIXME]
+
+ /***********************************
+ * EEPROM
+ ***********************************/
+
+ /***********************************
+ * NOR
+ ***********************************/
+ #define NORFLASH_MEMORY_PHY1 EXP_CS0_AXI_BASEADDR
+
+ /***********************************
+ * NAND
+ ***********************************/
+ #define COMCERTO_EXP_CS4_SEG_SZ 1
+
+ #define COMCERTO_NAND_FIO_ADDR EXP_CS4_AXI_BASEADDR
+ #define COMCERTO_NAND_BR 0x20000000 /* BR is on GPIO_29 */
+ #define COMCERTO_NAND_CE 0x10000000 /* CE is on GPIO_28 */
+ #define COMCERTO_NAND_IO_SZ ((COMCERTO_EXP_CS4_SEG_SZ << 12) +0x1000)
+
+ /***********************************
+ * SLIC
+ ***********************************/
+ #define COMCERTO_SLIC_GPIO_IRQ IRQ_G2
+
+#endif
diff --git a/arch/arm/mach-comcerto/include/mach/comcerto-common.h b/arch/arm/mach-comcerto/include/mach/comcerto-common.h
index 6a14993..f87b8a8 100644
--- a/arch/arm/mach-comcerto/include/mach/comcerto-common.h
+++ b/arch/arm/mach-comcerto/include/mach/comcerto-common.h
@@ -98,11 +98,6 @@
#define GEMAC_NO_PHY (1 << 0) // set if no phy connected to MAC (ex ethernet switch). In this case use MAC fixed configuration
#define GEMAC_PHY_RGMII_ADD_DELAY (1 << 1)
-/* gemac to interface name assignment */
-#define GEM0_ITF_NAME "eth0"
-#define GEM1_ITF_NAME "eth2"
-#define GEM2_ITF_NAME "eth3"
-
#define GEM0_MAC { 0x00, 0xED, 0xCD, 0xEF, 0xAA, 0xCC }
#define GEM1_MAC { 0x00, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E }
#define GEM2_MAC { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }
diff --git a/arch/arm/mach-comcerto/include/mach/debug-macro.S b/arch/arm/mach-comcerto/include/mach/debug-macro.S
index c1efb9b..345ac4c 100644
--- a/arch/arm/mach-comcerto/include/mach/debug-macro.S
+++ b/arch/arm/mach-comcerto/include/mach/debug-macro.S
@@ -22,14 +22,14 @@
.macro addruart, rx, rv, tmp
- moveq \rx, #0x96000000 @ physical base address
- @movne \rv, #0xf1600000 @ virtual base
+ ldr \rx, =0x96000000 @ physical base address
+ ldr \rv, =0xf1600000 @ virtual base
#ifdef CONFIG_COMCERTO_UART1_SUPPORT
- orr \rx, \rx, #0x00400000
- orr \rv, \rv, #0x00400000
+ add \rx, \rx, #0x00400000
+ add \rv, \rv, #0x00400000
#elif CONFIG_COMCERTO_UART0_SUPPORT
- orr \rx, \rx, #0x00300000
- orr \rv, \rv, #0x00300000
+ add \rx, \rx, #0x00300000
+ add \rv, \rv, #0x00300000
#else
#error no uart defined
#endif
diff --git a/arch/arm/mach-comcerto/include/mach/hardware.h b/arch/arm/mach-comcerto/include/mach/hardware.h
index 3099117..b86a3f1 100644
--- a/arch/arm/mach-comcerto/include/mach/hardware.h
+++ b/arch/arm/mach-comcerto/include/mach/hardware.h
@@ -34,6 +34,8 @@
/***** Board *****/
#if defined(CONFIG_C2K_ASIC)
#include <mach/board-c2kasic.h>
+ #elif defined(CONFIG_GOOGLE_FIBER_OPTIMUS)
+ #include <mach/board-optimus.h>
#elif defined(CONFIG_C2K_EVM)
#include <mach/board-c2kevm.h>
#elif defined(CONFIG_C2K_MFCN_EVM)
diff --git a/arch/arm/mach-comcerto/pcie-c2000.c b/arch/arm/mach-comcerto/pcie-c2000.c
index d4c01fb..e31d010 100644
--- a/arch/arm/mach-comcerto/pcie-c2000.c
+++ b/arch/arm/mach-comcerto/pcie-c2000.c
@@ -1842,8 +1842,7 @@
}
if (system_rev == 1) {
- printk(KERN_INFO "PCIe: Detected C2K RevA1 device serdes clk devider old:new=%x:%x\n",
- p_pcie_phy_reg_file[0x61].val, 0x06);
+ // C2K RevA1 devices use a different serdes clk divider
p_pcie_phy_reg_file[0x61].val = 0x6;
}
diff --git a/arch/arm/mach-comcerto/platsmp.c b/arch/arm/mach-comcerto/platsmp.c
index 7c0c727..568917b 100644
--- a/arch/arm/mach-comcerto/platsmp.c
+++ b/arch/arm/mach-comcerto/platsmp.c
@@ -106,22 +106,24 @@
wait_for_cpu1_hotplug_done:
/* Waiting for hotplug event invoked by CPU hotplug framework */
- wait_event(cpu1_hotplug, cpu1_hotplug_done>0);
+ pr_info("cpu1 waiting for hotplug event.\n");
+ wait_event_interruptible(cpu1_hotplug, cpu1_hotplug_done>0);
+ pr_info("cpu1 hotplug done!\n");
+ if (cpu1_hotplug_done > 0) {
#ifdef CONFIG_NEON
- __raw_writel((__raw_readl(A9DP_CPU_CLK_CNTRL) & ~NEON1_CLK_ENABLE), A9DP_CPU_CLK_CNTRL);
- __raw_writel((__raw_readl(A9DP_CPU_RESET) | NEON1_RST), A9DP_CPU_RESET);
+ __raw_writel((__raw_readl(A9DP_CPU_CLK_CNTRL) & ~NEON1_CLK_ENABLE), A9DP_CPU_CLK_CNTRL);
+ __raw_writel((__raw_readl(A9DP_CPU_RESET) | NEON1_RST), A9DP_CPU_RESET);
#endif
- __raw_writel((__raw_readl(A9DP_CPU_CLK_CNTRL) & ~CPU1_CLK_ENABLE), A9DP_CPU_CLK_CNTRL);
- __raw_writel((__raw_readl(A9DP_PWR_CNTRL) | CLAMP_CORE1), A9DP_PWR_CNTRL);
- __raw_writel((__raw_readl(A9DP_PWR_CNTRL) | CORE_PWRDWN1), A9DP_PWR_CNTRL);
- __raw_writel((__raw_readl(A9DP_CPU_RESET) | CPU1_RST), A9DP_CPU_RESET);
- __raw_writel((__raw_readl(A9DP_PWR_CNTRL) & ~CORE_PWRDWN1), A9DP_PWR_CNTRL);
+ __raw_writel((__raw_readl(A9DP_CPU_CLK_CNTRL) & ~CPU1_CLK_ENABLE), A9DP_CPU_CLK_CNTRL);
+ __raw_writel((__raw_readl(A9DP_PWR_CNTRL) | CLAMP_CORE1), A9DP_PWR_CNTRL);
+ __raw_writel((__raw_readl(A9DP_PWR_CNTRL) | CORE_PWRDWN1), A9DP_PWR_CNTRL);
+ __raw_writel((__raw_readl(A9DP_CPU_RESET) | CPU1_RST), A9DP_CPU_RESET);
+ __raw_writel((__raw_readl(A9DP_PWR_CNTRL) & ~CORE_PWRDWN1), A9DP_PWR_CNTRL);
- cpu1_hotplug_done = 0;
+ cpu1_hotplug_done = 0;
+ }
goto wait_for_cpu1_hotplug_done;
-
- return;
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 508cb29..5e6457a 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -47,10 +47,14 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/types.h>
/*
* Addresses to scan
- * Address is fully defined internally and cannot be changed.
+ * Address is fully defined internally and cannot be changed except for
+ * LM64 which has one pin dedicated to address selection.
+ * LM63 and LM96163 have address 0x4c.
+ * LM64 can have address 0x18 or 0x4e.
*/
static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
@@ -60,6 +64,7 @@
*/
#define LM63_REG_CONFIG1 0x03
+#define LM63_REG_CONVRATE 0x04
#define LM63_REG_CONFIG2 0xBF
#define LM63_REG_CONFIG_FAN 0x4A
@@ -70,6 +75,9 @@
#define LM63_REG_PWM_VALUE 0x4C
#define LM63_REG_PWM_FREQ 0x4D
+#define LM63_REG_LUT_TEMP_HYST 0x4F
+#define LM63_REG_LUT_TEMP(nr) (0x50 + 2 * (nr))
+#define LM63_REG_LUT_PWM(nr) (0x51 + 2 * (nr))
#define LM63_REG_LOCAL_TEMP 0x00
#define LM63_REG_LOCAL_HIGH 0x05
@@ -91,6 +99,16 @@
#define LM63_REG_MAN_ID 0xFE
#define LM63_REG_CHIP_ID 0xFF
+#define LM96163_REG_TRUTHERM 0x30
+#define LM96163_REG_REMOTE_TEMP_U_MSB 0x31
+#define LM96163_REG_REMOTE_TEMP_U_LSB 0x32
+#define LM96163_REG_CONFIG_ENHANCED 0x45
+
+#define LM63_MAX_CONVRATE 9
+
+#define LM63_MAX_CONVRATE_HZ 32
+#define LM96163_MAX_CONVRATE_HZ 26
+
/*
* Conversions and various macros
* For tachometer counts, the LM63 uses 16-bit values.
@@ -112,15 +130,24 @@
(val) >= 127000 ? 127 : \
(val) < 0 ? ((val) - 500) / 1000 : \
((val) + 500) / 1000)
+#define TEMP8U_TO_REG(val) ((val) <= 0 ? 0 : \
+ (val) >= 255000 ? 255 : \
+ ((val) + 500) / 1000)
#define TEMP11_FROM_REG(reg) ((reg) / 32 * 125)
#define TEMP11_TO_REG(val) ((val) <= -128000 ? 0x8000 : \
(val) >= 127875 ? 0x7FE0 : \
(val) < 0 ? ((val) - 62) / 125 * 32 : \
((val) + 62) / 125 * 32)
+#define TEMP11U_TO_REG(val) ((val) <= 0 ? 0 : \
+ (val) >= 255875 ? 0xFFE0 : \
+ ((val) + 62) / 125 * 32)
#define HYST_TO_REG(val) ((val) <= 0 ? 0 : \
(val) >= 127000 ? 127 : \
((val) + 500) / 1000)
+#define UPDATE_INTERVAL(max, rate) \
+ ((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
+
/*
* Functions declaration
*/
@@ -134,7 +161,7 @@
static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
static void lm63_init_client(struct i2c_client *client);
-enum chips { lm63, lm64 };
+enum chips { lm63, lm64, lm96163 };
/*
* Driver data (common to all clients)
@@ -143,6 +170,7 @@
static const struct i2c_device_id lm63_id[] = {
{ "lm63", lm63 },
{ "lm64", lm64 },
+ { "lm96163", lm96163 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm63_id);
@@ -167,26 +195,53 @@
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
+ char lut_valid; /* zero until lut fields are valid */
unsigned long last_updated; /* in jiffies */
- int kind;
+ unsigned long lut_last_updated; /* in jiffies */
+ enum chips kind;
int temp2_offset;
+ int update_interval; /* in milliseconds */
+ int max_convrate_hz;
+ int lut_size; /* 8 or 12 */
+
/* registers values */
u8 config, config_fan;
u16 fan[2]; /* 0: input
1: low limit */
u8 pwm1_freq;
- u8 pwm1_value;
- s8 temp8[3]; /* 0: local input
+ u8 pwm1[13]; /* 0: current output
+ 1-12: lookup table */
+ s8 temp8[15]; /* 0: local input
1: local high limit
- 2: remote critical limit */
- s16 temp11[3]; /* 0: remote input
+ 2: remote critical limit
+ 3-14: lookup table */
+ s16 temp11[4]; /* 0: remote input
1: remote low limit
- 2: remote high limit */
+ 2: remote high limit
+ 3: remote offset */
+ u16 temp11u; /* remote input (unsigned) */
u8 temp2_crit_hyst;
+ u8 lut_temp_hyst;
u8 alarms;
+ bool pwm_highres;
+ bool lut_temp_highres;
+ bool remote_unsigned; /* true if unsigned remote upper limits */
+ bool trutherm;
};
+static inline int temp8_from_reg(struct lm63_data *data, int nr)
+{
+ if (data->remote_unsigned)
+ return TEMP8_FROM_REG((u8)data->temp8[nr]);
+ return TEMP8_FROM_REG(data->temp8[nr]);
+}
+
+static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
+{
+ return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
+}
+
/*
* Sysfs callback functions and files
*/
@@ -204,7 +259,12 @@
{
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
- unsigned long val = simple_strtoul(buf, NULL, 10);
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err)
+ return err;
mutex_lock(&data->update_lock);
data->fan[1] = FAN_TO_REG(val);
@@ -216,13 +276,22 @@
return count;
}
-static ssize_t show_pwm1(struct device *dev, struct device_attribute *dummy,
+static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm63_data *data = lm63_update_device(dev);
- return sprintf(buf, "%d\n", data->pwm1_value >= 2 * data->pwm1_freq ?
- 255 : (data->pwm1_value * 255 + data->pwm1_freq) /
- (2 * data->pwm1_freq));
+ int nr = attr->index;
+ int pwm;
+
+ if (data->pwm_highres)
+ pwm = data->pwm1[nr];
+ else
+ pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
+ 255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
+ (2 * data->pwm1_freq);
+
+ return sprintf(buf, "%d\n", pwm);
}
static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
@@ -231,22 +300,26 @@
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
unsigned long val;
-
+ int err;
+
if (!(data->config_fan & 0x20)) /* register is read-only */
return -EPERM;
- val = simple_strtoul(buf, NULL, 10);
+ err = kstrtoul(buf, 10, &val);
+ if (err)
+ return err;
+
+ val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock);
- data->pwm1_value = val <= 0 ? 0 :
- val >= 255 ? 2 * data->pwm1_freq :
- (val * data->pwm1_freq * 2 + 127) / 255;
- i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1_value);
+ data->pwm1[0] = data->pwm_highres ? val :
+ (val * data->pwm1_freq * 2 + 127) / 255;
+ i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_pwm1_enable(struct device *dev, struct device_attribute *dummy,
- char *buf)
+static ssize_t show_pwm1_enable(struct device *dev,
+ struct device_attribute *dummy, char *buf)
{
struct lm63_data *data = lm63_update_device(dev);
return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
@@ -273,21 +346,47 @@
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm63_data *data = lm63_update_device(dev);
- return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[attr->index])
+ return sprintf(buf, "%d\n", temp8_from_reg(data, attr->index)
+ data->temp2_offset);
}
-static ssize_t set_local_temp8(struct device *dev,
- struct device_attribute *dummy,
- const char *buf, size_t count)
+static ssize_t show_lut_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm63_data *data = lm63_update_device(dev);
+ return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
+ + data->temp2_offset);
+}
+
+static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
- long val = simple_strtol(buf, NULL, 10);
+ int nr = attr->index;
+ int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH;
+ long val;
+ int err;
+ int temp;
+
+ err = kstrtol(buf, 10, &val);
+ if (err)
+ return err;
mutex_lock(&data->update_lock);
- data->temp8[1] = TEMP8_TO_REG(val);
- i2c_smbus_write_byte_data(client, LM63_REG_LOCAL_HIGH, data->temp8[1]);
+ if (nr == 2) {
+ if (data->remote_unsigned)
+ temp = TEMP8U_TO_REG(val - data->temp2_offset);
+ else
+ temp = TEMP8_TO_REG(val - data->temp2_offset);
+ } else {
+ temp = TEMP8_TO_REG(val);
+ }
+ data->temp8[nr] = temp;
+ i2c_smbus_write_byte_data(client, reg, temp);
mutex_unlock(&data->update_lock);
return count;
}
@@ -297,28 +396,56 @@
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm63_data *data = lm63_update_device(dev);
- return sprintf(buf, "%d\n", TEMP11_FROM_REG(data->temp11[attr->index])
- + data->temp2_offset);
+ int nr = attr->index;
+ int temp;
+
+ if (!nr) {
+ /*
+ * Use unsigned temperature unless its value is zero.
+ * If it is zero, use signed temperature.
+ */
+ if (data->temp11u)
+ temp = TEMP11_FROM_REG(data->temp11u);
+ else
+ temp = TEMP11_FROM_REG(data->temp11[nr]);
+ } else {
+ if (data->remote_unsigned && nr == 2)
+ temp = TEMP11_FROM_REG((u16)data->temp11[nr]);
+ else
+ temp = TEMP11_FROM_REG(data->temp11[nr]);
+ }
+ return sprintf(buf, "%d\n", temp + data->temp2_offset);
}
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- static const u8 reg[4] = {
+ static const u8 reg[6] = {
LM63_REG_REMOTE_LOW_MSB,
LM63_REG_REMOTE_LOW_LSB,
LM63_REG_REMOTE_HIGH_MSB,
LM63_REG_REMOTE_HIGH_LSB,
+ LM63_REG_REMOTE_OFFSET_MSB,
+ LM63_REG_REMOTE_OFFSET_LSB,
};
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
- long val = simple_strtol(buf, NULL, 10);
+ long val;
+ int err;
int nr = attr->index;
+ err = kstrtol(buf, 10, &val);
+ if (err)
+ return err;
+
mutex_lock(&data->update_lock);
- data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
+ if (data->remote_unsigned && nr == 2)
+ data->temp11[nr] = TEMP11U_TO_REG(val - data->temp2_offset);
+ else
+ data->temp11[nr] = TEMP11_TO_REG(val - data->temp2_offset);
+
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2],
data->temp11[nr] >> 8);
i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1],
@@ -327,35 +454,143 @@
return count;
}
-/* Hysteresis register holds a relative value, while we want to present
- an absolute to user-space */
-static ssize_t show_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
- char *buf)
+/*
+ * Hysteresis register holds a relative value, while we want to present
+ * an absolute to user-space
+ */
+static ssize_t show_temp2_crit_hyst(struct device *dev,
+ struct device_attribute *dummy, char *buf)
{
struct lm63_data *data = lm63_update_device(dev);
- return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->temp8[2])
+ return sprintf(buf, "%d\n", temp8_from_reg(data, 2)
+ data->temp2_offset
- TEMP8_FROM_REG(data->temp2_crit_hyst));
}
-/* And now the other way around, user-space provides an absolute
- hysteresis value and we have to store a relative one */
-static ssize_t set_temp2_crit_hyst(struct device *dev, struct device_attribute *dummy,
+static ssize_t show_lut_temp_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm63_data *data = lm63_update_device(dev);
+
+ return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
+ + data->temp2_offset
+ - TEMP8_FROM_REG(data->lut_temp_hyst));
+}
+
+/*
+ * And now the other way around, user-space provides an absolute
+ * hysteresis value and we have to store a relative one
+ */
+static ssize_t set_temp2_crit_hyst(struct device *dev,
+ struct device_attribute *dummy,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
- long val = simple_strtol(buf, NULL, 10);
+ long val;
+ int err;
long hyst;
+ err = kstrtol(buf, 10, &val);
+ if (err)
+ return err;
+
mutex_lock(&data->update_lock);
- hyst = TEMP8_FROM_REG(data->temp8[2]) + data->temp2_offset - val;
+ hyst = temp8_from_reg(data, 2) + data->temp2_offset - val;
i2c_smbus_write_byte_data(client, LM63_REG_REMOTE_TCRIT_HYST,
HYST_TO_REG(hyst));
mutex_unlock(&data->update_lock);
return count;
}
+/*
+ * Set conversion rate.
+ * client->update_lock must be held when calling this function.
+ */
+static void lm63_set_convrate(struct i2c_client *client, struct lm63_data *data,
+ unsigned int interval)
+{
+ int i;
+ unsigned int update_interval;
+
+ /* Shift calculations to avoid rounding errors */
+ interval <<= 6;
+
+ /* find the nearest update rate */
+ update_interval = (1 << (LM63_MAX_CONVRATE + 6)) * 1000
+ / data->max_convrate_hz;
+ for (i = 0; i < LM63_MAX_CONVRATE; i++, update_interval >>= 1)
+ if (interval >= update_interval * 3 / 4)
+ break;
+
+ i2c_smbus_write_byte_data(client, LM63_REG_CONVRATE, i);
+ data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i);
+}
+
+static ssize_t show_update_interval(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lm63_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm63_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ lm63_set_convrate(client, data, SENSORS_LIMIT(val, 0, 100000));
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm63_data *data = i2c_get_clientdata(client);
+
+ return sprintf(buf, data->trutherm ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm63_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+ int ret;
+ u8 reg;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+ if (val != 1 && val != 2)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->trutherm = val == 1;
+ reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02;
+ i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM,
+ reg | (data->trutherm ? 0x02 : 0x00));
+ data->valid = 0;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
char *buf)
{
@@ -377,27 +612,87 @@
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
set_fan, 1);
-static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO,
+ show_lut_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO,
+ show_lut_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO,
+ show_lut_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO,
+ show_lut_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO,
+ show_lut_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO,
+ show_lut_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO,
+ show_lut_temp, NULL, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO,
+ show_lut_temp, NULL, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO,
+ show_lut_temp, NULL, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO,
+ show_lut_temp, NULL, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO,
+ show_lut_temp, NULL, 13);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 13);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO,
+ show_lut_temp, NULL, 14);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO,
+ show_lut_temp_hyst, NULL, 14);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_local_temp8, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_local_temp8,
- set_local_temp8, 1);
+ set_temp8, 1);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp11,
set_temp11, 1);
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp11,
set_temp11, 2);
-/*
- * On LM63, temp2_crit can be set only once, which should be job
- * of the bootloader.
- */
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+ set_temp11, 3);
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8,
- NULL, 2);
+ set_temp8, 2);
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
set_temp2_crit_hyst);
+static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type);
+
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
@@ -408,14 +703,43 @@
/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+ set_update_interval);
+
static struct attribute *lm63_attributes[] = {
- &dev_attr_pwm1.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
&dev_attr_pwm1_enable.attr,
+ &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point3_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point4_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point5_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point6_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point7_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point8_temp_hyst.dev_attr.attr,
+
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&dev_attr_temp2_crit_hyst.attr,
@@ -425,10 +749,54 @@
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_update_interval.attr,
NULL
};
+static struct attribute *lm63_attributes_extra_lut[] = {
+ &sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point9_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point10_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point11_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point11_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point11_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point12_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point12_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point12_temp_hyst.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group lm63_group_extra_lut = {
+ .attrs = lm63_attributes_extra_lut,
+};
+
+/*
+ * On LM63, temp2_crit can be set only once, which should be job
+ * of the bootloader.
+ * On LM64, temp2_crit can always be set.
+ * On LM96163, temp2_crit can be set if bit 1 of the configuration
+ * register is true.
+ */
+static umode_t lm63_attribute_mode(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm63_data *data = i2c_get_clientdata(client);
+
+ if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr
+ && (data->kind == lm64 ||
+ (data->kind == lm96163 && (data->config & 0x02))))
+ return attr->mode | S_IWUSR;
+
+ return attr->mode;
+}
+
static const struct attribute_group lm63_group = {
+ .is_visible = lm63_attribute_mode,
.attrs = lm63_attributes,
};
@@ -487,6 +855,8 @@
strlcpy(info->type, "lm63", I2C_NAME_SIZE);
else if (chip_id == 0x51 && (address == 0x18 || address == 0x4e))
strlcpy(info->type, "lm64", I2C_NAME_SIZE);
+ else if (chip_id == 0x49 && address == 0x4c)
+ strlcpy(info->type, "lm96163", I2C_NAME_SIZE);
else
return -ENODEV;
@@ -518,12 +888,24 @@
lm63_init_client(new_client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj,
- &lm63_group)))
+ err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
+ if (err)
goto exit_free;
if (data->config & 0x04) { /* tachometer enabled */
- if ((err = sysfs_create_group(&new_client->dev.kobj,
- &lm63_group_fan1)))
+ err = sysfs_create_group(&new_client->dev.kobj,
+ &lm63_group_fan1);
+ if (err)
+ goto exit_remove_files;
+ }
+ if (data->kind == lm96163) {
+ err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_type);
+ if (err)
+ goto exit_remove_files;
+
+ err = sysfs_create_group(&new_client->dev.kobj,
+ &lm63_group_extra_lut);
+ if (err)
goto exit_remove_files;
}
@@ -538,17 +920,25 @@
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
+ if (data->kind == lm96163) {
+ device_remove_file(&new_client->dev, &dev_attr_temp2_type);
+ sysfs_remove_group(&new_client->dev.kobj,
+ &lm63_group_extra_lut);
+ }
exit_free:
kfree(data);
exit:
return err;
}
-/* Idealy we shouldn't have to initialize anything, since the BIOS
- should have taken care of everything */
+/*
+ * Ideally we shouldn't have to initialize anything, since the BIOS
+ * should have taken care of everything
+ */
static void lm63_init_client(struct i2c_client *client)
{
struct lm63_data *data = i2c_get_clientdata(client);
+ u8 convrate;
data->config = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
data->config_fan = i2c_smbus_read_byte_data(client,
@@ -561,16 +951,57 @@
i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
data->config);
}
+ /* Tachometer is always enabled on LM64 */
+ if (data->kind == lm64)
+ data->config |= 0x04;
/* We may need pwm1_freq before ever updating the client data */
data->pwm1_freq = i2c_smbus_read_byte_data(client, LM63_REG_PWM_FREQ);
if (data->pwm1_freq == 0)
data->pwm1_freq = 1;
+ switch (data->kind) {
+ case lm63:
+ case lm64:
+ data->max_convrate_hz = LM63_MAX_CONVRATE_HZ;
+ data->lut_size = 8;
+ break;
+ case lm96163:
+ data->max_convrate_hz = LM96163_MAX_CONVRATE_HZ;
+ data->lut_size = 12;
+ data->trutherm
+ = i2c_smbus_read_byte_data(client,
+ LM96163_REG_TRUTHERM) & 0x02;
+ break;
+ }
+ convrate = i2c_smbus_read_byte_data(client, LM63_REG_CONVRATE);
+ if (unlikely(convrate > LM63_MAX_CONVRATE))
+ convrate = LM63_MAX_CONVRATE;
+ data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz,
+ convrate);
+
+ /*
+ * For LM96163, check if high resolution PWM
+ * and unsigned temperature format is enabled.
+ */
+ if (data->kind == lm96163) {
+ u8 config_enhanced
+ = i2c_smbus_read_byte_data(client,
+ LM96163_REG_CONFIG_ENHANCED);
+ if (config_enhanced & 0x20)
+ data->lut_temp_highres = true;
+ if ((config_enhanced & 0x10)
+ && !(data->config_fan & 0x08) && data->pwm1_freq == 8)
+ data->pwm_highres = true;
+ if (config_enhanced & 0x08)
+ data->remote_unsigned = true;
+ }
+
/* Show some debug info about the LM63 configuration */
- dev_dbg(&client->dev, "Alert/tach pin configured for %s\n",
- (data->config & 0x04) ? "tachometer input" :
- "alert output");
+ if (data->kind == lm63)
+ dev_dbg(&client->dev, "Alert/tach pin configured for %s\n",
+ (data->config & 0x04) ? "tachometer input" :
+ "alert output");
dev_dbg(&client->dev, "PWM clock %s kHz, output frequency %u Hz\n",
(data->config_fan & 0x08) ? "1.4" : "360",
((data->config_fan & 0x08) ? 700 : 180000) / data->pwm1_freq);
@@ -586,6 +1017,10 @@
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm63_group);
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
+ if (data->kind == lm96163) {
+ device_remove_file(&client->dev, &dev_attr_temp2_type);
+ sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut);
+ }
kfree(data);
return 0;
@@ -595,10 +1030,15 @@
{
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
+ unsigned long next_update;
+ int i;
mutex_lock(&data->update_lock);
- if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ next_update = data->last_updated
+ + msecs_to_jiffies(data->update_interval) + 1;
+
+ if (time_after(jiffies, next_update) || !data->valid) {
if (data->config & 0x04) { /* tachometer enabled */
/* order matters for fan1_input */
data->fan[0] = i2c_smbus_read_byte_data(client,
@@ -615,8 +1055,8 @@
LM63_REG_PWM_FREQ);
if (data->pwm1_freq == 0)
data->pwm1_freq = 1;
- data->pwm1_value = i2c_smbus_read_byte_data(client,
- LM63_REG_PWM_VALUE);
+ data->pwm1[0] = i2c_smbus_read_byte_data(client,
+ LM63_REG_PWM_VALUE);
data->temp8[0] = i2c_smbus_read_byte_data(client,
LM63_REG_LOCAL_TEMP);
@@ -636,6 +1076,17 @@
LM63_REG_REMOTE_HIGH_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_HIGH_LSB);
+ data->temp11[3] = (i2c_smbus_read_byte_data(client,
+ LM63_REG_REMOTE_OFFSET_MSB) << 8)
+ | i2c_smbus_read_byte_data(client,
+ LM63_REG_REMOTE_OFFSET_LSB);
+
+ if (data->kind == lm96163)
+ data->temp11u = (i2c_smbus_read_byte_data(client,
+ LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
+ | i2c_smbus_read_byte_data(client,
+ LM96163_REG_REMOTE_TEMP_U_LSB);
+
data->temp8[2] = i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TCRIT);
data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
@@ -648,6 +1099,21 @@
data->valid = 1;
}
+ if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
+ !data->lut_valid) {
+ for (i = 0; i < data->lut_size; i++) {
+ data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
+ LM63_REG_LUT_PWM(i));
+ data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
+ LM63_REG_LUT_TEMP(i));
+ }
+ data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
+ LM63_REG_LUT_TEMP_HYST);
+
+ data->lut_last_updated = jiffies;
+ data->lut_valid = 1;
+ }
+
mutex_unlock(&data->update_lock);
return data;
diff --git a/drivers/i2c/busses/i2c-comcerto.c b/drivers/i2c/busses/i2c-comcerto.c
index c2c8649..0898123 100644
--- a/drivers/i2c/busses/i2c-comcerto.c
+++ b/drivers/i2c/busses/i2c-comcerto.c
@@ -632,7 +632,7 @@
else
i2c->irq = -1;
- if (i2c_add_adapter(&comcerto_i2c_adapter) != 0) {
+ if (i2c_add_numbered_adapter(&comcerto_i2c_adapter) != 0) {
dev_err(i2c->dev, "%s: failed to add I2C adapter\n", __FUNCTION__);
goto err3;
}
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index ddf9ec6..37c2449 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -155,7 +155,13 @@
/* test for options */
if (strncmp(s, "ro", 2) == 0)
{
+#if 0
+ /* It turns out that if you have a bootloader which marks
+ * its partitions read-only, and you don't want it to do so,
+ * you have trouble updating it BECAUSE IT IS READONLY.
+ * <sob>. */
mask_flags |= MTD_WRITEABLE;
+#endif
s += 2;
}
diff --git a/drivers/mtd/nand/comcerto_nand.c b/drivers/mtd/nand/comcerto_nand.c
index c23439a..3f19fa8 100644
--- a/drivers/mtd/nand/comcerto_nand.c
+++ b/drivers/mtd/nand/comcerto_nand.c
@@ -23,6 +23,7 @@
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#include <linux/delay.h>
+#include <linux/ratelimit.h>
#include <linux/platform_device.h>
#include <mach/ecc.h>
@@ -323,13 +324,13 @@
if (!((readl_relaxed(ecc_base_addr + ECC_CORR_DONE_STAT)) & ECC_DONE)) {
temp_nand_ecc_errors[0] += 1 ;
- printk(KERN_WARNING "ECC: uncorrectable error 1 !!!\n");
+ printk_ratelimited(KERN_WARNING "ECC: uncorrectable error 1 !!!\n");
return -1;
}
/* Check if the block has uncorrectable number of errors */
if ((readl_relaxed(ecc_base_addr + ECC_CORR_STAT)) & ECC_UNCORR) {
- printk(KERN_WARNING "ECC: uncorrectable error 2 !!!\n");
+ printk_ratelimited(KERN_WARNING "ECC: uncorrectable error 2 !!!\n");
temp_nand_ecc_errors[1] += 1 ;
return -EIO;
}
@@ -582,6 +583,7 @@
nand_device->ecc.read_page = comcerto_nand_read_page_hwecc;
nand_device->ecc.calculate = comcerto_calculate_ecc;
nand_device->ecc.correct = comcerto_correct_ecc;
+ printk("hw_syndrome correction %d.\n", mtd->writesize);
switch (mtd->writesize) {
case 512:
@@ -651,13 +653,16 @@
nand_device->ecc.total = nand_device->ecc.steps * nand_device->ecc.bytes;
+#if 0
nand_device->bbt_td = &bbt_main_descr;
nand_device->bbt_md = &bbt_mirror_descr;
+#endif
nand_device->badblock_pattern = &c2000_badblock_pattern;
nand_device->bbt_options |= NAND_BBT_USE_FLASH;
} else {
- nand_device->ecc.mode = NAND_ECC_SOFT;
+ printk("using soft ecc.\n");
+ nand_device->ecc.mode = NAND_ECC_SOFT_BCH;
}
#endif
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ed4d76d..32de310 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -39,6 +39,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/ratelimit.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
@@ -1420,6 +1421,49 @@
return NULL;
}
+/*
+ * NOTE(apenwarr): Newer kernels do this much better.
+ * Among other things, they report a max_flips value that's the largest
+ * number of flips in any 1024-byte ECC calculation, as opposed to the total
+ * flips in the whole 4096-byte page. The latter is dangerous because
+ * you could see 24 flips in a single 1024-byte region, which is the edge
+ * of disaster, even though it's only 1/4 of the maximum 96 flips we could
+ * handle if averaged across 4 pages. So where we'd like to set a threshold
+ * per 1024-byte region, we instead have to set a threshold per
+ * 4096-byte region that *still* must be well under 24.
+ *
+ * Anyway, this code can go away someday when we use a newer kernel.
+ */
+static int unclean_if_too_many_flips(struct mtd_info *mtd,
+ struct mtd_ecc_stats *stats) {
+ uint32_t flips = mtd->ecc_stats.corrected - stats->corrected;
+ uint32_t threshold;
+ switch (mtd->oobsize) {
+ case 8:
+ case 16:
+ case 64:
+ threshold = 0;
+ break;
+ case 128:
+ threshold = 4;
+ break;
+ case 224:
+ threshold = 18;
+ break;
+ default:
+ threshold = 0;
+ break;
+ }
+ if (flips > threshold / 2) {
+ // This should be very rare, bu we want to know as we
+ // approach our threshold, which should be even more rare.
+ printk_ratelimited(KERN_WARNING
+ "ECC: corrected %d bits (threshold=%d)\n",
+ flips, threshold);
+ }
+ return flips > threshold ? -EUCLEAN : 0;
+}
+
/**
* nand_do_read_ops - [INTERN] Read data with ECC
* @mtd: MTD device structure
@@ -1566,7 +1610,7 @@
if (mtd->ecc_stats.failed - stats.failed)
return -EBADMSG;
- return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+ return unclean_if_too_many_flips(mtd, &stats);
}
/**
@@ -1848,7 +1892,7 @@
if (mtd->ecc_stats.failed - stats.failed)
return -EBADMSG;
- return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+ return unclean_if_too_many_flips(mtd, &stats);
}
/**
@@ -2593,8 +2637,13 @@
chip->page_shift, 0, allowbbt)) {
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
__func__, page);
+#if 0
+ // NOTE(apenwarr): for us it's ok to erase bad blocks.
+ // UBI deals with bad blocks a different way.
+ // And we don't trust our bad block detection logic.
instr->state = MTD_ERASE_FAILED;
goto erase_exit;
+#endif
}
/*
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index 3803e0b..8202379 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -28,6 +28,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_bch.h>
#include <linux/bch.h>
+#include <linux/ratelimit.h>
/**
* struct nand_bch_control - private NAND BCH control structure
@@ -97,7 +98,7 @@
errloc[i]);
}
} else if (count < 0) {
- printk(KERN_ERR "ecc unrecoverable error\n");
+ printk_ratelimited(KERN_ERR "ecc unrecoverable error\n");
count = -1;
}
return count;
diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c
index ef238ca..d44ff7b 100644
--- a/drivers/net/phy/atheros.c
+++ b/drivers/net/phy/atheros.c
@@ -35,6 +35,7 @@
#define PHY_ID_AR8035 0x004dd072
#define PHY_ID_AR8033 0x004dd074
#define PHY_ID_AR8327 0x004dd033
+#define PHY_ID_AR8337 0x004dd034
MODULE_DESCRIPTION("Atheros PHY driver");
MODULE_LICENSE("GPL");
@@ -152,6 +153,25 @@
.driver = { .owner = THIS_MODULE,},
};
+/* Atheros Ar8337 */
+static struct phy_driver ar8337_driver = {
+ .phy_id = PHY_ID_AR8337,
+ .name = "Atheros AR8337",
+ .phy_id_mask = 0xffffff00,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &ar8x_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &ar8x_ack_interrupt,
+ .config_intr = &ar8x_config_intr,
+#ifdef CONFIG_PM
+ .suspend = &genphy_suspend,
+ .resume = &genphy_resume,
+#endif
+ .driver = { .owner = THIS_MODULE,},
+};
+
static int __init ar8x_init(void)
{
int err;
@@ -164,6 +184,12 @@
if (err < 0)
phy_driver_unregister(&ar8035_driver);
+ err = phy_driver_register(&ar8337_driver);
+ if (err < 0) {
+ phy_driver_unregister(&ar8035_driver);
+ phy_driver_unregister(&ar8327_driver);
+ }
+
return err;
}
@@ -171,6 +197,7 @@
{
phy_driver_unregister(&ar8035_driver);
phy_driver_unregister(&ar8327_driver);
+ phy_driver_unregister(&ar8337_driver);
}
module_init(ar8x_init);
@@ -179,6 +206,7 @@
static struct mdio_device_id __maybe_unused atheros_tbl[] = {
{ PHY_ID_AR8035, 0xffffff00 },
{ PHY_ID_AR8327, 0xffffff00 },
+ { PHY_ID_AR8337, 0xffffff00 },
{ }
};
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 5e2046b..4211ede 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -129,7 +129,9 @@
static void dwspi_baudcfg(struct designware_spi *dwspi, u32 speed_hz)
{
- u16 div = (speed_hz) ? dwspi->ssi_clk/speed_hz : 0xffff;
+ /* Divisor must be an even number */
+ u16 div = (speed_hz) ? DIV_ROUND_UP(dwspi->ssi_clk, speed_hz) + 1 &
+ 0xfffe : 0xffff;
writew(div, dwspi->regs + DWSPI_BAUDR);
}
@@ -434,7 +436,7 @@
/* This delay should be good enough for 100KHz spi transfers. Slower
* transfers may need a longer delay.
*/
- udelay(10);
+ //udelay(10);
/* get remaining rx bytes */
do {
diff --git a/drivers/watchdog/comcerto_wdt.c b/drivers/watchdog/comcerto_wdt.c
index d89aeb2..da497c0 100644
--- a/drivers/watchdog/comcerto_wdt.c
+++ b/drivers/watchdog/comcerto_wdt.c
@@ -29,6 +29,7 @@
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/clk.h>
+#include <linux/timer.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -37,25 +38,38 @@
#include <mach/reset.h>
#define WDT_NAME "comcerto_wdt"
+
+/* these are the actual wdt limits */
#define WDT_DEFAULT_TIMEOUT 5
#define WDT_MAX_TIMEOUT (0xffffffff / COMCERTO_AHBCLK)
+/* these are for the virtual wdt */
+#define WDT_DEFAULT_TIME 70 /* seconds */
+#define WDT_MAX_TIME 255 /* seconds */
+
static unsigned long COMCERTO_AHBCLK;
static int wd_heartbeat = WDT_DEFAULT_TIMEOUT;
+static int wd_time = WDT_DEFAULT_TIME;
static int nowayout = WATCHDOG_NOWAYOUT;
static struct clk *clk_axi;
module_param(wd_heartbeat, int, 0);
MODULE_PARM_DESC(wd_heartbeat, "Watchdog heartbeat in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")");
+module_param(wd_time, int, 0);
+MODULE_PARM_DESC(wd_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
+
#ifdef CONFIG_WATCHDOG_NOWAYOUT
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
#endif
+static struct timer_list wdt_timer;
+
static unsigned long comcerto_wdt_busy;
static char expect_close;
static spinlock_t wdt_lock;
+static atomic_t ticks;
/*
* Inform whether the boot was caused by AXI watchdog or not.
@@ -95,12 +109,46 @@
/*
* Write wd_heartbeat to high bound register.
*/
-static void comcerto_wdt_set_timeout(void)
+static void comcerto_wdt_pet_watchdog_physical(void)
{
__raw_writel(wd_heartbeat * COMCERTO_AHBCLK, COMCERTO_TIMER_WDT_HIGH_BOUND);
}
/*
+ * reset virtual wdt timer
+ */
+static void comcerto_wdt_pet_watchdog_virtual(void)
+{
+ atomic_set(&ticks, wd_time);
+}
+
+/*
+ * set virtual wd timeout reset value
+ */
+static int comcerto_wdt_settimeout(int new_time)
+{
+ if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
+ return -EINVAL;
+
+ wd_time = new_time;
+ return 0;
+}
+
+/*
+ * implement virtual wdt on physical wdt with timer
+ */
+static void comcerto_timer_tick(unsigned long unused)
+{
+ if (!atomic_dec_and_test(&ticks)) {
+ comcerto_wdt_pet_watchdog_physical();
+ mod_timer(&wdt_timer, jiffies + HZ);
+ //printk(KERN_CRIT WDT_NAME ": Watchdog will fire in %d secs\n", atomic_read(&ticks));
+ } else {
+ printk(KERN_CRIT WDT_NAME ": Watchdog will fire soon!!!\n");
+ }
+}
+
+/*
* Disable the watchdog.
*/
static void comcerto_wdt_stop(void)
@@ -110,13 +158,15 @@
spin_lock_irqsave(&wdt_lock, flags);
+ del_timer(&wdt_timer);
+
wdt_control = __raw_readl(COMCERTO_TIMER_WDT_CONTROL);
__raw_writel(wdt_control & ~COMCERTO_TIMER_WDT_CONTROL_TIMER_ENABLE, COMCERTO_TIMER_WDT_CONTROL);
spin_unlock_irqrestore(&wdt_lock, flags);
- comcerto_wdt_set_timeout();
+ comcerto_wdt_pet_watchdog_physical();
}
/*
@@ -135,6 +185,8 @@
comcerto_rst_cntrl_set(AXI_WD_RST_EN);
+ mod_timer(&wdt_timer, jiffies + HZ);
+
spin_unlock_irqrestore(&wdt_lock, flags);
}
@@ -150,7 +202,7 @@
{
comcerto_wdt_stop();
- __raw_writel(~0, COMCERTO_TIMER_WDT_HIGH_BOUND); /* write max timout */
+ __raw_writel(~0, COMCERTO_TIMER_WDT_HIGH_BOUND); /* write max timeout */
}
/*
@@ -161,7 +213,8 @@
if (test_and_set_bit(0, &comcerto_wdt_busy))
return -EBUSY;
- comcerto_wdt_set_timeout();
+ comcerto_wdt_pet_watchdog_virtual();
+ comcerto_wdt_pet_watchdog_physical();
comcerto_wdt_start();
return nonseekable_open(inode, file);
@@ -204,7 +257,7 @@
switch(cmd) {
case WDIOC_KEEPALIVE:
- comcerto_wdt_set_timeout();
+ comcerto_wdt_pet_watchdog_virtual();
break;
case WDIOC_GETSUPPORT:
@@ -221,18 +274,18 @@
goto err;
}
- if (comcerto_wdt_set_heartbeat(new_value)) {
+ if (comcerto_wdt_settimeout(new_value)) {
err = -EINVAL;
goto err;
}
- comcerto_wdt_set_timeout();
+ comcerto_wdt_pet_watchdog_virtual();
- return put_user(wd_heartbeat, p);
+ return put_user(wd_time, p);
break;
case WDIOC_GETTIMEOUT:
- return put_user(wd_heartbeat, p);
+ return put_user(wd_time, p);
break;
case WDIOC_GETSTATUS:
@@ -291,7 +344,7 @@
}
}
- comcerto_wdt_set_timeout();
+ comcerto_wdt_pet_watchdog_virtual();
}
return len;
@@ -352,6 +405,16 @@
WDT_NAME, WDT_MAX_TIMEOUT, WDT_DEFAULT_TIMEOUT);
}
+ /* check that the time value is within range; if not reset to the default */
+ if (comcerto_wdt_settimeout(wd_time)) {
+ comcerto_wdt_settimeout(WDT_DEFAULT_TIMEOUT);
+
+ printk(KERN_INFO "%s: wd_time value is out of range: 1..%lu, using %d\n",
+ WDT_NAME, WDT_MAX_TIME, WDT_DEFAULT_TIME);
+ }
+
+ setup_timer(&wdt_timer, comcerto_timer_tick, 0L);
+
return 0;
err_misc:
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index b09ba2d..5047b57 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -2802,6 +2802,8 @@
val = d->chk_fs;
else if (dent == d->dfs_tst_rcvry)
val = d->tst_rcvry;
+ else if (dent == d->dfs_readonly)
+ val = c->ro_error;
else
return -EINVAL;
@@ -2993,6 +2995,12 @@
goto out_remove;
d->dfs_tst_rcvry = dent;
+ fname = "readonly";
+ dent = debugfs_create_file(fname, S_IRUSR, d->dfs_dir, c, &dfs_fops);
+ if (IS_ERR_OR_NULL(dent))
+ goto out_remove;
+ d->dfs_readonly = dent;
+
return 0;
out_remove:
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index c9d2941..1a244ac 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -81,6 +81,7 @@
* @dfs_chk_lprops: debugfs knob to enable UBIFS LEP properties extra checks
* @dfs_chk_fs: debugfs knob to enable UBIFS contents extra checks
* @dfs_tst_rcvry: debugfs knob to enable UBIFS recovery testing
+ * @dfs_readonly: debugfs file to get ro_error state
*/
struct ubifs_debug_info {
struct ubifs_zbranch old_zroot;
@@ -124,6 +125,7 @@
struct dentry *dfs_chk_lprops;
struct dentry *dfs_chk_fs;
struct dentry *dfs_tst_rcvry;
+ struct dentry *dfs_readonly;
};
/**
diff --git a/init/Kconfig b/init/Kconfig
index de390b3..a846f22 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1009,6 +1009,44 @@
very difficult to diagnose system problems, saying N here is
strongly discouraged.
+config PRINTK_PERSIST
+ default n
+ bool "printk log persists across reboots" if PRINTK
+ help
+ This option tries to keep the printk memory buffer in a well-known
+ location in physical memory. It isn't cleared on reboot (unless RAM
+ is wiped by your boot loader or BIOS) so if your system crashes
+ or panics, you might get to examine all the log messages next time you
+ boot. The persisted log messages show up in your 'dmesg' output.
+ Use log_buf_len= to specify the size of the persistent memory buffer.
+ A value of 0 turns off this feature.
+
+config PRINTK_PERSIST_BUF_SHIFT
+ int "Printk persist buffer size (16 => 64KB, 23 => 8MB)"
+ range 16 23
+ depends on PRINTK_PERSIST
+ default 23
+ help
+ The printk persist buffer is a log buffer that persists across reboots.
+ Select buffer size as a power of 2.
+ Examples:
+ 17 => 128 KB
+ 16 => 64 KB
+ 15 => 32 KB
+ 14 => 16 KB
+ 13 => 8 KB
+ 12 => 4 KB
+
+config BOOTLOG_COPY
+ default n
+ depends on PRINTK_PERSIST
+ bool "copy boot log to printk log" if PRINTK
+ help
+ This option copies the boot log stored in bootlog memory and save it
+ in the printk log.
+ Note: you must supply the bootlog= and log_buf_len= kernel parameters
+ to activate this feature.
+
config BUG
bool "BUG() support" if EXPERT
default y
diff --git a/kernel/panic.c b/kernel/panic.c
index 3458469..bd00edd 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -27,13 +27,13 @@
#define PANIC_TIMER_STEP 100
#define PANIC_BLINK_SPD 18
-int panic_on_oops;
+int panic_on_oops = 1;
static unsigned long tainted_mask;
static int pause_on_oops;
static int pause_on_oops_flag;
static DEFINE_SPINLOCK(pause_on_oops_lock);
-int panic_timeout;
+int panic_timeout = 3;
EXPORT_SYMBOL_GPL(panic_timeout);
ATOMIC_NOTIFIER_HEAD(panic_notifier_list);
diff --git a/kernel/printk.c b/kernel/printk.c
index 7982a0a..40a766c 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -111,7 +111,12 @@
*/
static unsigned log_start; /* Index into log_buf: next char to be read by syslog() */
static unsigned con_start; /* Index into log_buf: next char to be sent to consoles */
+
+#ifdef CONFIG_PRINTK_PERSIST
+#define log_end logbits->_log_end
+#else
static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */
+#endif
/*
* If exclusive_console is non-NULL then only this console is to be printed to.
@@ -144,12 +149,6 @@
#ifdef CONFIG_PRINTK
-static char __log_buf[__LOG_BUF_LEN];
-static char *log_buf = __log_buf;
-static int log_buf_len = __LOG_BUF_LEN;
-static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
-static int saved_console_loglevel = -1;
-
#ifdef CONFIG_KEXEC
/*
* This appends the listed symbols to /proc/vmcoreinfo
@@ -168,8 +167,163 @@
}
#endif
+static int saved_console_loglevel = -1;
+static char __log_buf[__LOG_BUF_LEN];
+static char *log_buf = __log_buf;
+
+#ifndef CONFIG_PRINTK_PERSIST
+
+static int log_buf_len = __LOG_BUF_LEN;
+static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
+
+static __init char *log_buf_alloc(unsigned long size, unsigned *dest_offset)
+{
+ return alloc_bootmem(size);
+}
+
+#else /* CONFIG_PRINTK_PERSIST */
+
+struct logbits {
+ int magic; /* needed to verify the memory across reboots */
+ int _log_buf_len; /* leading _ so they aren't replaced by #define */
+ unsigned _logged_chars;
+ unsigned _log_end;
+};
+static struct logbits __logbits = {
+ ._log_buf_len = __LOG_BUF_LEN,
+};
+static struct logbits *logbits = &__logbits;
+#define log_buf_len logbits->_log_buf_len
+#define logged_chars logbits->_logged_chars
+
+#define PERSIST_SEARCH_START 0
+#define PERSIST_SEARCH_END 0xfe000000
+#define PERSIST_SEARCH_JUMP (16*1024*1024)
+#define PERSIST_MAGIC 0xbabb1e
+
+#ifdef CONFIG_BOOTLOG_COPY
+#define BOOTLOG_MAGIC (0x1090091e)
+struct bloghdr {
+ unsigned int magic; /* for kernel verification */
+ unsigned int offset; /* current log offset */
+};
+
+extern unsigned long bootlog_get_addr(void);
+extern unsigned long bootlog_get_size(void);
+extern void bootlog_free(void);
+
+static inline struct bloghdr *get_bootlog_hdr(void)
+{
+ unsigned long bootlog_size = bootlog_get_size();
+ if (bootlog_size) {
+ struct bloghdr *blog_hdr = (struct bloghdr *)
+ phys_to_virt(bootlog_get_addr());
+ if (BOOTLOG_MAGIC != blog_hdr->magic ||
+ (blog_hdr->offset + sizeof(struct bloghdr) >
+ bootlog_size)) {
+ printk(KERN_INFO "bootlog: header invalid m:0x%08x "
+ "o:0x%08x s:0x%08lx\n", blog_hdr->magic,
+ blog_hdr->offset, bootlog_size);
+ return NULL;
+ }
+ return blog_hdr;
+ }
+ return NULL;
+}
+
+static inline unsigned copy_bootlog(struct bloghdr *blog_hdr,
+ unsigned dest_offset)
+{
+ if (blog_hdr) {
+ unsigned idx = dest_offset;
+ char *blog_buf = (char *)(blog_hdr + 1);
+ unsigned i;
+
+ for (i = 0; i < blog_hdr->offset; ++i) {
+ LOG_BUF(idx) = blog_buf[i];
+ ++idx;
+ }
+ if (logged_chars + blog_hdr->offset <= log_buf_len)
+ logged_chars += blog_hdr->offset;
+ else
+ logged_chars = log_buf_len;
+ dest_offset = idx;
+ }
+ return dest_offset;
+}
+
+static inline void free_bootlog(void)
+{
+ bootlog_free();
+}
+
+#endif
+
+/*
+ * size is a power of 2 so that the printk offset mask will work. We'll add
+ * a bit more space to the end of the buffer for our extra data, but that
+ * won't change the offset of the buffers.
+ */
+static __init char *log_buf_alloc(unsigned long size, unsigned *dest_offset)
+{
+ unsigned long where;
+ char *buf;
+ unsigned long full_size = size + sizeof(struct logbits);
+ struct logbits *new_logbits;
+
+ for (where = PERSIST_SEARCH_END - size;
+ where >= PERSIST_SEARCH_START;
+ where -= PERSIST_SEARCH_JUMP) {
+ if (reserve_bootmem(where, full_size, BOOTMEM_EXCLUSIVE))
+ continue;
+
+ buf = phys_to_virt(where);
+ new_logbits = phys_to_virt(where + size);
+ printk(KERN_INFO "printk_persist: memory reserved @ 0x%08lx\n",
+ where);
+ if (new_logbits->magic != PERSIST_MAGIC ||
+ new_logbits->_log_buf_len != size ||
+ new_logbits->_logged_chars > size) {
+ printk(KERN_INFO "printk_persist: header invalid, "
+ "cleared.\n");
+ memset(buf, 0, full_size);
+ new_logbits->magic = PERSIST_MAGIC;
+ new_logbits->_log_buf_len = size;
+ new_logbits->_logged_chars = 0;
+ new_logbits->_log_end = 0;
+ } else {
+ printk(KERN_INFO "printk_persist: header valid; "
+ "logged=%d next=%d\n",
+ new_logbits->_logged_chars,
+ new_logbits->_log_end);
+ }
+ *dest_offset = new_logbits->_log_end;
+ new_logbits->_log_end = log_end;
+ if (new_logbits->_logged_chars + logged_chars <= size)
+ new_logbits->_logged_chars += logged_chars;
+ else
+ new_logbits->_logged_chars = size;
+ logbits = new_logbits;
+ return buf;
+ }
+ goto error;
+
+error:
+ /* replace the buffer, but don't bother to swap struct logbits */
+ printk(KERN_ERR "printk_persist: failed to reserve bootmem "
+ "area. disabled.\n");
+ return alloc_bootmem(full_size);
+}
+#endif /* CONFIG_PRINTK_PERSIST */
+
/* requested log_buf_len from kernel cmdline */
-static unsigned long __initdata new_log_buf_len;
+static unsigned long __initdata new_log_buf_len =
+#ifdef CONFIG_PRINTK_PERSIST_BUF_SHIFT
+ (1 << CONFIG_PRINTK_PERSIST_BUF_SHIFT)
+#else
+ 0
+#endif
+;
/* save requested log_buf_len since it's too early to process it */
static int __init log_buf_len_setup(char *str)
@@ -178,7 +332,7 @@
if (size)
size = roundup_pow_of_two(size);
- if (size > log_buf_len)
+ if (size > log_buf_len || size == 0)
new_log_buf_len = size;
return 0;
@@ -188,9 +342,12 @@
void __init setup_log_buf(int early)
{
unsigned long flags;
- unsigned start, dest_idx, offset;
- char *new_log_buf;
+ unsigned start, dest_offset = 0, dest_idx, offset;
+ char *new_log_buf = NULL;
int free;
+#ifdef CONFIG_BOOTLOG_COPY
+ struct bloghdr *blog_hdr = NULL;
+#endif
if (!new_log_buf_len)
return;
@@ -203,7 +360,7 @@
return;
new_log_buf = __va(mem);
} else {
- new_log_buf = alloc_bootmem_nopanic(new_log_buf_len);
+ new_log_buf = log_buf_alloc(new_log_buf_len, &dest_offset);
}
if (unlikely(!new_log_buf)) {
@@ -212,26 +369,39 @@
return;
}
+#ifdef CONFIG_BOOTLOG_COPY
+ /* Read out the blog_hdr before logbuf is locked in case print
+ * is needed. */
+ blog_hdr = get_bootlog_hdr();
+#endif
+
raw_spin_lock_irqsave(&logbuf_lock, flags);
log_buf_len = new_log_buf_len;
log_buf = new_log_buf;
- new_log_buf_len = 0;
free = __LOG_BUF_LEN - log_end;
+#ifdef CONFIG_BOOTLOG_COPY
+ dest_offset = copy_bootlog(blog_hdr, dest_offset);
+#endif
offset = start = min(con_start, log_start);
- dest_idx = 0;
+ dest_idx = dest_offset;
while (start != log_end) {
unsigned log_idx_mask = start & (__LOG_BUF_LEN - 1);
+ unsigned dest_idx_mask = dest_idx & (new_log_buf_len - 1);
- log_buf[dest_idx] = __log_buf[log_idx_mask];
+ log_buf[dest_idx_mask] = __log_buf[log_idx_mask];
start++;
dest_idx++;
}
- log_start -= offset;
- con_start -= offset;
- log_end -= offset;
+ log_start += dest_offset - offset;
+ con_start += dest_offset - offset;
+ log_end += dest_offset - offset;
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+#ifdef CONFIG_BOOTLOG_COPY
+ free_bootlog();
+#endif
+
pr_info("log_buf_len: %d\n", log_buf_len);
pr_info("early log buf free: %d(%d%%)\n",
free, (free * 100) / __LOG_BUF_LEN);
@@ -329,8 +499,11 @@
return 0;
}
+#define COPY_SIZE 4096
+
int do_syslog(int type, char __user *buf, int len, bool from_file)
{
+ char *copybuf;
unsigned i, j, limit, count;
int do_clear = 0;
char c;
@@ -396,6 +569,11 @@
error = -EFAULT;
goto out;
}
+ copybuf = kmalloc(COPY_SIZE, GFP_KERNEL);
+ if (!copybuf) {
+ error = -ENOMEM;
+ goto out;
+ }
count = len;
if (count > log_buf_len)
count = log_buf_len;
@@ -406,7 +584,7 @@
logged_chars = 0;
limit = log_end;
/*
- * __put_user() could sleep, and while we sleep
+ * copy_to_user() could sleep, and while we sleep
* printk() could overwrite the messages
* we try to copy to user space. Therefore
* the messages are copied in reverse. <manfreds>
@@ -416,14 +594,26 @@
if (j + log_buf_len < log_end)
break;
c = LOG_BUF(j);
- raw_spin_unlock_irq(&logbuf_lock);
- error = __put_user(c,&buf[count-1-i]);
- cond_resched();
- raw_spin_lock_irq(&logbuf_lock);
+ copybuf[COPY_SIZE-1-(i % COPY_SIZE)] = c;
+ if ((i+1) % COPY_SIZE == 0) {
+ raw_spin_unlock_irq(&logbuf_lock);
+ error = copy_to_user(&buf[count-1-i],
+ copybuf, COPY_SIZE);
+ cond_resched();
+ raw_spin_lock_irq(&logbuf_lock);
+ }
}
raw_spin_unlock_irq(&logbuf_lock);
- if (error)
- break;
+ if (!error) {
+ /* in case copybuf was only partially filled */
+ error = copy_to_user(&buf[count-i],
+ copybuf + COPY_SIZE - (i % COPY_SIZE),
+ i % COPY_SIZE);
+ }
+ if (error) {
+ error = -EFAULT;
+ goto copy_done;
+ }
error = i;
if (i != count) {
int offset = count-error;
@@ -437,6 +627,8 @@
cond_resched();
}
}
+copy_done:
+ kfree(copybuf);
break;
/* Clear ring buffer */
case SYSLOG_ACTION_CLEAR:
@@ -911,13 +1103,11 @@
for (i = 0; i < plen; i++)
emit_log_char(printk_buf[i]);
- printed_len += plen;
} else {
/* Add log prefix */
emit_log_char('<');
emit_log_char(current_log_level + '0');
emit_log_char('>');
- printed_len += 3;
}
if (printk_time) {
@@ -935,7 +1125,6 @@
for (tp = tbuf; tp < tbuf + tlen; tp++)
emit_log_char(*tp);
- printed_len += tlen;
}
if (!*p)
diff --git a/mm/bootmem.c b/mm/bootmem.c
index d514f27..a5cbc05 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -352,7 +352,8 @@
return 0;
pos = bdata->node_low_pfn;
}
- BUG();
+ //BUG();
+ return -ENXIO;
}
/**
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d325941..9b9be63 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -853,6 +853,24 @@
n->fclone = SKB_FCLONE_UNAVAILABLE;
}
+#if defined(CONFIG_COMCERTO_CUSTOM_SKB_LAYOUT)
+ if (skb->mspd_data) {
+ if (skb->mspd_len) {
+ int ofst = skb->len - skb->mspd_len;
+
+ memcpy(skb->data + ofst, skb->mspd_data + skb->mspd_ofst, skb->mspd_len);
+ skb->mspd_len = 0;
+ }
+
+ WARN_ON(skb_shared(skb));
+
+ if (!skb_shared(skb)) {
+ kfree(skb->mspd_data);
+ skb->mspd_data = NULL;
+ }
+ }
+#endif
+
return __skb_clone(n, skb);
}
EXPORT_SYMBOL(skb_clone);
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 5701c8d..7b6f708 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -98,13 +98,18 @@
nf_ct_l3proto_try_module_get(unsigned short l3proto)
{
int ret;
+ int retried = 0;
struct nf_conntrack_l3proto *p;
retry: p = nf_ct_l3proto_find_get(l3proto);
if (p == &nf_conntrack_l3proto_generic) {
- ret = request_module("nf_conntrack-%d", l3proto);
- if (!ret)
- goto retry;
+ if (!retried) {
+ ret = request_module("nf_conntrack-%d", l3proto);
+ if (!ret) {
+ retried = 1;
+ goto retry;
+ }
+ }
return -EPROTOTYPE;
}