mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-29 07:18:51 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
34
arch/mips/loongson/common/Makefile
Normal file
34
arch/mips/loongson/common/Makefile
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# Makefile for loongson based machines.
|
||||
#
|
||||
|
||||
obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \
|
||||
bonito-irq.o mem.o machtype.o platform.o
|
||||
obj-$(CONFIG_GPIOLIB) += gpio.o
|
||||
obj-$(CONFIG_PCI) += pci.o
|
||||
|
||||
#
|
||||
# Serial port support
|
||||
#
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
loongson-serial-$(CONFIG_SERIAL_8250) := serial.o
|
||||
obj-y += $(loongson-serial-m) $(loongson-serial-y)
|
||||
obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
|
||||
obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
|
||||
|
||||
#
|
||||
# Enable CS5536 Virtual Support Module(VSM) to virtulize the PCI configure
|
||||
# space
|
||||
#
|
||||
obj-$(CONFIG_CS5536) += cs5536/
|
||||
|
||||
#
|
||||
# Suspend Support
|
||||
#
|
||||
|
||||
obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o
|
||||
|
||||
#
|
||||
# Big Memory (SWIOTLB) Support
|
||||
#
|
||||
obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o
|
||||
53
arch/mips/loongson/common/bonito-irq.c
Normal file
53
arch/mips/loongson/common/bonito-irq.c
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
|
||||
* Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org)
|
||||
*
|
||||
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
|
||||
* Author: Fuxin Zhang, zhangfx@lemote.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include <loongson.h>
|
||||
|
||||
static inline void bonito_irq_enable(struct irq_data *d)
|
||||
{
|
||||
LOONGSON_INTENSET = (1 << (d->irq - LOONGSON_IRQ_BASE));
|
||||
mmiowb();
|
||||
}
|
||||
|
||||
static inline void bonito_irq_disable(struct irq_data *d)
|
||||
{
|
||||
LOONGSON_INTENCLR = (1 << (d->irq - LOONGSON_IRQ_BASE));
|
||||
mmiowb();
|
||||
}
|
||||
|
||||
static struct irq_chip bonito_irq_type = {
|
||||
.name = "bonito_irq",
|
||||
.irq_mask = bonito_irq_disable,
|
||||
.irq_unmask = bonito_irq_enable,
|
||||
};
|
||||
|
||||
static struct irqaction __maybe_unused dma_timeout_irqaction = {
|
||||
.handler = no_action,
|
||||
.name = "dma_timeout",
|
||||
};
|
||||
|
||||
void bonito_irq_init(void)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = LOONGSON_IRQ_BASE; i < LOONGSON_IRQ_BASE + 32; i++)
|
||||
irq_set_chip_and_handler(i, &bonito_irq_type,
|
||||
handle_level_irq);
|
||||
|
||||
#ifdef CONFIG_CPU_LOONGSON2E
|
||||
setup_irq(LOONGSON_IRQ_BASE + 10, &dma_timeout_irqaction);
|
||||
#endif
|
||||
}
|
||||
48
arch/mips/loongson/common/cmdline.c
Normal file
48
arch/mips/loongson/common/cmdline.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Based on Ocelot Linux port, which is
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: jsun@mvista.com or jsun@junsun.net
|
||||
*
|
||||
* Copyright 2003 ICT CAS
|
||||
* Author: Michael Guo <guoyi@ict.ac.cn>
|
||||
*
|
||||
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
|
||||
* Author: Fuxin Zhang, zhangfx@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
#include <loongson.h>
|
||||
|
||||
void __init prom_init_cmdline(void)
|
||||
{
|
||||
int prom_argc;
|
||||
/* pmon passes arguments in 32bit pointers */
|
||||
int *_prom_argv;
|
||||
int i;
|
||||
long l;
|
||||
|
||||
/* firmware arguments are initialized in head.S */
|
||||
prom_argc = fw_arg0;
|
||||
_prom_argv = (int *)fw_arg1;
|
||||
|
||||
/* arg[0] is "g", the rest is boot parameters */
|
||||
arcs_cmdline[0] = '\0';
|
||||
for (i = 1; i < prom_argc; i++) {
|
||||
l = (long)_prom_argv[i];
|
||||
if (strlen(arcs_cmdline) + strlen(((char *)l) + 1)
|
||||
>= sizeof(arcs_cmdline))
|
||||
break;
|
||||
strcat(arcs_cmdline, ((char *)l));
|
||||
strcat(arcs_cmdline, " ");
|
||||
}
|
||||
|
||||
prom_init_machtype();
|
||||
}
|
||||
11
arch/mips/loongson/common/cs5536/Makefile
Normal file
11
arch/mips/loongson/common/cs5536/Makefile
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# Makefile for CS5536 support.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
|
||||
cs5536_isa.o cs5536_ehci.o
|
||||
|
||||
#
|
||||
# Enable cs5536 mfgpt Timer
|
||||
#
|
||||
obj-$(CONFIG_CS5536_MFGPT) += cs5536_mfgpt.o
|
||||
140
arch/mips/loongson/common/cs5536/cs5536_acc.c
Normal file
140
arch/mips/loongson/common/cs5536/cs5536_acc.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* the ACC Virtual Support Module of AMD CS5536
|
||||
*
|
||||
* Copyright (C) 2007 Lemote, Inc.
|
||||
* Author : jlliu, liujl@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <cs5536/cs5536.h>
|
||||
#include <cs5536/cs5536_pci.h>
|
||||
|
||||
void pci_acc_write_reg(int reg, u32 value)
|
||||
{
|
||||
u32 hi = 0, lo = value;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_COMMAND:
|
||||
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
|
||||
if (value & PCI_COMMAND_MASTER)
|
||||
lo |= (0x03 << 8);
|
||||
else
|
||||
lo &= ~(0x03 << 8);
|
||||
_wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo);
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
if (value & PCI_STATUS_PARITY) {
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
if (lo & SB_PARE_ERR_FLAG) {
|
||||
lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
|
||||
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PCI_BAR0_REG:
|
||||
if (value == PCI_BAR_RANGE_MASK) {
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
lo |= SOFT_BAR_ACC_FLAG;
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else if (value & 0x01) {
|
||||
value &= 0xfffffffc;
|
||||
hi = 0xA0000000 | ((value & 0x000ff000) >> 12);
|
||||
lo = 0x000fff80 | ((value & 0x00000fff) << 20);
|
||||
_wrmsr(GLIU_MSR_REG(GLIU_IOD_BM1), hi, lo);
|
||||
}
|
||||
break;
|
||||
case PCI_ACC_INT_REG:
|
||||
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
|
||||
/* disable all the usb interrupt in PIC */
|
||||
lo &= ~(0xf << PIC_YSEL_LOW_ACC_SHIFT);
|
||||
if (value) /* enable all the acc interrupt in PIC */
|
||||
lo |= (CS5536_ACC_INTR << PIC_YSEL_LOW_ACC_SHIFT);
|
||||
_wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 pci_acc_read_reg(int reg)
|
||||
{
|
||||
u32 hi, lo;
|
||||
u32 conf_data = 0;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_ACC_DEVICE_ID, CS5536_VENDOR_ID);
|
||||
break;
|
||||
case PCI_COMMAND:
|
||||
_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
|
||||
if (((lo & 0xfff00000) || (hi & 0x000000ff))
|
||||
&& ((hi & 0xf0000000) == 0xa0000000))
|
||||
conf_data |= PCI_COMMAND_IO;
|
||||
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
|
||||
if ((lo & 0x300) == 0x300)
|
||||
conf_data |= PCI_COMMAND_MASTER;
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
conf_data |= PCI_STATUS_66MHZ;
|
||||
conf_data |= PCI_STATUS_FAST_BACK;
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
if (lo & SB_PARE_ERR_FLAG)
|
||||
conf_data |= PCI_STATUS_PARITY;
|
||||
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
|
||||
break;
|
||||
case PCI_CLASS_REVISION:
|
||||
_rdmsr(ACC_MSR_REG(ACC_CAP), &hi, &lo);
|
||||
conf_data = lo & 0x000000ff;
|
||||
conf_data |= (CS5536_ACC_CLASS_CODE << 8);
|
||||
break;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
conf_data =
|
||||
CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
|
||||
PCI_NORMAL_LATENCY_TIMER);
|
||||
break;
|
||||
case PCI_BAR0_REG:
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
if (lo & SOFT_BAR_ACC_FLAG) {
|
||||
conf_data = CS5536_ACC_RANGE |
|
||||
PCI_BASE_ADDRESS_SPACE_IO;
|
||||
lo &= ~SOFT_BAR_ACC_FLAG;
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else {
|
||||
_rdmsr(GLIU_MSR_REG(GLIU_IOD_BM1), &hi, &lo);
|
||||
conf_data = (hi & 0x000000ff) << 12;
|
||||
conf_data |= (lo & 0xfff00000) >> 20;
|
||||
conf_data |= 0x01;
|
||||
conf_data &= ~0x02;
|
||||
}
|
||||
break;
|
||||
case PCI_CARDBUS_CIS:
|
||||
conf_data = PCI_CARDBUS_CIS_POINTER;
|
||||
break;
|
||||
case PCI_SUBSYSTEM_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_ACC_SUB_ID, CS5536_SUB_VENDOR_ID);
|
||||
break;
|
||||
case PCI_ROM_ADDRESS:
|
||||
conf_data = PCI_EXPANSION_ROM_BAR;
|
||||
break;
|
||||
case PCI_CAPABILITY_LIST:
|
||||
conf_data = PCI_CAPLIST_USB_POINTER;
|
||||
break;
|
||||
case PCI_INTERRUPT_LINE:
|
||||
conf_data =
|
||||
CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_ACC_INTR);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return conf_data;
|
||||
}
|
||||
160
arch/mips/loongson/common/cs5536/cs5536_ehci.c
Normal file
160
arch/mips/loongson/common/cs5536/cs5536_ehci.c
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* the EHCI Virtual Support Module of AMD CS5536
|
||||
*
|
||||
* Copyright (C) 2007 Lemote, Inc.
|
||||
* Author : jlliu, liujl@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <cs5536/cs5536.h>
|
||||
#include <cs5536/cs5536_pci.h>
|
||||
|
||||
void pci_ehci_write_reg(int reg, u32 value)
|
||||
{
|
||||
u32 hi = 0, lo = value;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_COMMAND:
|
||||
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
|
||||
if (value & PCI_COMMAND_MASTER)
|
||||
hi |= PCI_COMMAND_MASTER;
|
||||
else
|
||||
hi &= ~PCI_COMMAND_MASTER;
|
||||
|
||||
if (value & PCI_COMMAND_MEMORY)
|
||||
hi |= PCI_COMMAND_MEMORY;
|
||||
else
|
||||
hi &= ~PCI_COMMAND_MEMORY;
|
||||
_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
if (value & PCI_STATUS_PARITY) {
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
if (lo & SB_PARE_ERR_FLAG) {
|
||||
lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
|
||||
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PCI_BAR0_REG:
|
||||
if (value == PCI_BAR_RANGE_MASK) {
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
lo |= SOFT_BAR_EHCI_FLAG;
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else if ((value & 0x01) == 0x00) {
|
||||
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
|
||||
lo = value;
|
||||
_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
|
||||
|
||||
value &= 0xfffffff0;
|
||||
hi = 0x40000000 | ((value & 0xff000000) >> 24);
|
||||
lo = 0x000fffff | ((value & 0x00fff000) << 8);
|
||||
_wrmsr(GLIU_MSR_REG(GLIU_P2D_BM4), hi, lo);
|
||||
}
|
||||
break;
|
||||
case PCI_EHCI_LEGSMIEN_REG:
|
||||
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
|
||||
hi &= 0x003f0000;
|
||||
hi |= (value & 0x3f) << 16;
|
||||
_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
|
||||
break;
|
||||
case PCI_EHCI_FLADJ_REG:
|
||||
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
|
||||
hi &= ~0x00003f00;
|
||||
hi |= value & 0x00003f00;
|
||||
_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 pci_ehci_read_reg(int reg)
|
||||
{
|
||||
u32 conf_data = 0;
|
||||
u32 hi, lo;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_EHCI_DEVICE_ID, CS5536_VENDOR_ID);
|
||||
break;
|
||||
case PCI_COMMAND:
|
||||
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
|
||||
if (hi & PCI_COMMAND_MASTER)
|
||||
conf_data |= PCI_COMMAND_MASTER;
|
||||
if (hi & PCI_COMMAND_MEMORY)
|
||||
conf_data |= PCI_COMMAND_MEMORY;
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
conf_data |= PCI_STATUS_66MHZ;
|
||||
conf_data |= PCI_STATUS_FAST_BACK;
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
if (lo & SB_PARE_ERR_FLAG)
|
||||
conf_data |= PCI_STATUS_PARITY;
|
||||
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
|
||||
break;
|
||||
case PCI_CLASS_REVISION:
|
||||
_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
|
||||
conf_data = lo & 0x000000ff;
|
||||
conf_data |= (CS5536_EHCI_CLASS_CODE << 8);
|
||||
break;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
conf_data =
|
||||
CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
|
||||
PCI_NORMAL_LATENCY_TIMER);
|
||||
break;
|
||||
case PCI_BAR0_REG:
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
if (lo & SOFT_BAR_EHCI_FLAG) {
|
||||
conf_data = CS5536_EHCI_RANGE |
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY;
|
||||
lo &= ~SOFT_BAR_EHCI_FLAG;
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else {
|
||||
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
|
||||
conf_data = lo & 0xfffff000;
|
||||
}
|
||||
break;
|
||||
case PCI_CARDBUS_CIS:
|
||||
conf_data = PCI_CARDBUS_CIS_POINTER;
|
||||
break;
|
||||
case PCI_SUBSYSTEM_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_EHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
|
||||
break;
|
||||
case PCI_ROM_ADDRESS:
|
||||
conf_data = PCI_EXPANSION_ROM_BAR;
|
||||
break;
|
||||
case PCI_CAPABILITY_LIST:
|
||||
conf_data = PCI_CAPLIST_USB_POINTER;
|
||||
break;
|
||||
case PCI_INTERRUPT_LINE:
|
||||
conf_data =
|
||||
CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
|
||||
break;
|
||||
case PCI_EHCI_LEGSMIEN_REG:
|
||||
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
|
||||
conf_data = (hi & 0x003f0000) >> 16;
|
||||
break;
|
||||
case PCI_EHCI_LEGSMISTS_REG:
|
||||
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
|
||||
conf_data = (hi & 0x3f000000) >> 24;
|
||||
break;
|
||||
case PCI_EHCI_FLADJ_REG:
|
||||
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
|
||||
conf_data = hi & 0x00003f00;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return conf_data;
|
||||
}
|
||||
192
arch/mips/loongson/common/cs5536/cs5536_ide.c
Normal file
192
arch/mips/loongson/common/cs5536/cs5536_ide.c
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* the IDE Virtual Support Module of AMD CS5536
|
||||
*
|
||||
* Copyright (C) 2007 Lemote, Inc.
|
||||
* Author : jlliu, liujl@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <cs5536/cs5536.h>
|
||||
#include <cs5536/cs5536_pci.h>
|
||||
|
||||
void pci_ide_write_reg(int reg, u32 value)
|
||||
{
|
||||
u32 hi = 0, lo = value;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_COMMAND:
|
||||
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
|
||||
if (value & PCI_COMMAND_MASTER)
|
||||
lo |= (0x03 << 4);
|
||||
else
|
||||
lo &= ~(0x03 << 4);
|
||||
_wrmsr(GLIU_MSR_REG(GLIU_PAE), hi, lo);
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
if (value & PCI_STATUS_PARITY) {
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
if (lo & SB_PARE_ERR_FLAG) {
|
||||
lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
|
||||
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
value &= 0x0000ff00;
|
||||
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
|
||||
hi &= 0xffffff00;
|
||||
hi |= (value >> 8);
|
||||
_wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
|
||||
break;
|
||||
case PCI_BAR4_REG:
|
||||
if (value == PCI_BAR_RANGE_MASK) {
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
lo |= SOFT_BAR_IDE_FLAG;
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else if (value & 0x01) {
|
||||
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
|
||||
lo = (value & 0xfffffff0) | 0x1;
|
||||
_wrmsr(IDE_MSR_REG(IDE_IO_BAR), hi, lo);
|
||||
|
||||
value &= 0xfffffffc;
|
||||
hi = 0x60000000 | ((value & 0x000ff000) >> 12);
|
||||
lo = 0x000ffff0 | ((value & 0x00000fff) << 20);
|
||||
_wrmsr(GLIU_MSR_REG(GLIU_IOD_BM2), hi, lo);
|
||||
}
|
||||
break;
|
||||
case PCI_IDE_CFG_REG:
|
||||
if (value == CS5536_IDE_FLASH_SIGNATURE) {
|
||||
_rdmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), &hi, &lo);
|
||||
lo |= 0x01;
|
||||
_wrmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), hi, lo);
|
||||
} else {
|
||||
_rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
|
||||
lo = value;
|
||||
_wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo);
|
||||
}
|
||||
break;
|
||||
case PCI_IDE_DTC_REG:
|
||||
_rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
|
||||
lo = value;
|
||||
_wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
|
||||
break;
|
||||
case PCI_IDE_CAST_REG:
|
||||
_rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
|
||||
lo = value;
|
||||
_wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
|
||||
break;
|
||||
case PCI_IDE_ETC_REG:
|
||||
_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
|
||||
lo = value;
|
||||
_wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
|
||||
break;
|
||||
case PCI_IDE_PM_REG:
|
||||
_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
|
||||
lo = value;
|
||||
_wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 pci_ide_read_reg(int reg)
|
||||
{
|
||||
u32 conf_data = 0;
|
||||
u32 hi, lo;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_IDE_DEVICE_ID, CS5536_VENDOR_ID);
|
||||
break;
|
||||
case PCI_COMMAND:
|
||||
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
|
||||
if (lo & 0xfffffff0)
|
||||
conf_data |= PCI_COMMAND_IO;
|
||||
_rdmsr(GLIU_MSR_REG(GLIU_PAE), &hi, &lo);
|
||||
if ((lo & 0x30) == 0x30)
|
||||
conf_data |= PCI_COMMAND_MASTER;
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
conf_data |= PCI_STATUS_66MHZ;
|
||||
conf_data |= PCI_STATUS_FAST_BACK;
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
if (lo & SB_PARE_ERR_FLAG)
|
||||
conf_data |= PCI_STATUS_PARITY;
|
||||
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
|
||||
break;
|
||||
case PCI_CLASS_REVISION:
|
||||
_rdmsr(IDE_MSR_REG(IDE_CAP), &hi, &lo);
|
||||
conf_data = lo & 0x000000ff;
|
||||
conf_data |= (CS5536_IDE_CLASS_CODE << 8);
|
||||
break;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
|
||||
hi &= 0x000000f8;
|
||||
conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE, hi);
|
||||
break;
|
||||
case PCI_BAR4_REG:
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
if (lo & SOFT_BAR_IDE_FLAG) {
|
||||
conf_data = CS5536_IDE_RANGE |
|
||||
PCI_BASE_ADDRESS_SPACE_IO;
|
||||
lo &= ~SOFT_BAR_IDE_FLAG;
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else {
|
||||
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
|
||||
conf_data = lo & 0xfffffff0;
|
||||
conf_data |= 0x01;
|
||||
conf_data &= ~0x02;
|
||||
}
|
||||
break;
|
||||
case PCI_CARDBUS_CIS:
|
||||
conf_data = PCI_CARDBUS_CIS_POINTER;
|
||||
break;
|
||||
case PCI_SUBSYSTEM_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_IDE_SUB_ID, CS5536_SUB_VENDOR_ID);
|
||||
break;
|
||||
case PCI_ROM_ADDRESS:
|
||||
conf_data = PCI_EXPANSION_ROM_BAR;
|
||||
break;
|
||||
case PCI_CAPABILITY_LIST:
|
||||
conf_data = PCI_CAPLIST_POINTER;
|
||||
break;
|
||||
case PCI_INTERRUPT_LINE:
|
||||
conf_data =
|
||||
CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_IDE_INTR);
|
||||
break;
|
||||
case PCI_IDE_CFG_REG:
|
||||
_rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
|
||||
conf_data = lo;
|
||||
break;
|
||||
case PCI_IDE_DTC_REG:
|
||||
_rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
|
||||
conf_data = lo;
|
||||
break;
|
||||
case PCI_IDE_CAST_REG:
|
||||
_rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
|
||||
conf_data = lo;
|
||||
break;
|
||||
case PCI_IDE_ETC_REG:
|
||||
_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
|
||||
conf_data = lo;
|
||||
break;
|
||||
case PCI_IDE_PM_REG:
|
||||
_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
|
||||
conf_data = lo;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return conf_data;
|
||||
}
|
||||
330
arch/mips/loongson/common/cs5536/cs5536_isa.c
Normal file
330
arch/mips/loongson/common/cs5536/cs5536_isa.c
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
* the ISA Virtual Support Module of AMD CS5536
|
||||
*
|
||||
* Copyright (C) 2007 Lemote, Inc.
|
||||
* Author : jlliu, liujl@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <cs5536/cs5536.h>
|
||||
#include <cs5536/cs5536_pci.h>
|
||||
|
||||
/* common variables for PCI_ISA_READ/WRITE_BAR */
|
||||
static const u32 divil_msr_reg[6] = {
|
||||
DIVIL_MSR_REG(DIVIL_LBAR_SMB), DIVIL_MSR_REG(DIVIL_LBAR_GPIO),
|
||||
DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), DIVIL_MSR_REG(DIVIL_LBAR_IRQ),
|
||||
DIVIL_MSR_REG(DIVIL_LBAR_PMS), DIVIL_MSR_REG(DIVIL_LBAR_ACPI),
|
||||
};
|
||||
|
||||
static const u32 soft_bar_flag[6] = {
|
||||
SOFT_BAR_SMB_FLAG, SOFT_BAR_GPIO_FLAG, SOFT_BAR_MFGPT_FLAG,
|
||||
SOFT_BAR_IRQ_FLAG, SOFT_BAR_PMS_FLAG, SOFT_BAR_ACPI_FLAG,
|
||||
};
|
||||
|
||||
static const u32 sb_msr_reg[6] = {
|
||||
SB_MSR_REG(SB_R0), SB_MSR_REG(SB_R1), SB_MSR_REG(SB_R2),
|
||||
SB_MSR_REG(SB_R3), SB_MSR_REG(SB_R4), SB_MSR_REG(SB_R5),
|
||||
};
|
||||
|
||||
static const u32 bar_space_range[6] = {
|
||||
CS5536_SMB_RANGE, CS5536_GPIO_RANGE, CS5536_MFGPT_RANGE,
|
||||
CS5536_IRQ_RANGE, CS5536_PMS_RANGE, CS5536_ACPI_RANGE,
|
||||
};
|
||||
|
||||
static const int bar_space_len[6] = {
|
||||
CS5536_SMB_LENGTH, CS5536_GPIO_LENGTH, CS5536_MFGPT_LENGTH,
|
||||
CS5536_IRQ_LENGTH, CS5536_PMS_LENGTH, CS5536_ACPI_LENGTH,
|
||||
};
|
||||
|
||||
/*
|
||||
* enable the divil module bar space.
|
||||
*
|
||||
* For all the DIVIL module LBAR, you should control the DIVIL LBAR reg
|
||||
* and the RCONFx(0~5) reg to use the modules.
|
||||
*/
|
||||
static void divil_lbar_enable(void)
|
||||
{
|
||||
u32 hi, lo;
|
||||
int offset;
|
||||
|
||||
/*
|
||||
* The DIVIL IRQ is not used yet. and make the RCONF0 reserved.
|
||||
*/
|
||||
|
||||
for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
|
||||
_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
|
||||
hi |= 0x01;
|
||||
_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* disable the divil module bar space.
|
||||
*/
|
||||
static void divil_lbar_disable(void)
|
||||
{
|
||||
u32 hi, lo;
|
||||
int offset;
|
||||
|
||||
for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
|
||||
_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
|
||||
hi &= ~0x01;
|
||||
_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BAR write: write value to the n BAR
|
||||
*/
|
||||
|
||||
void pci_isa_write_bar(int n, u32 value)
|
||||
{
|
||||
u32 hi = 0, lo = value;
|
||||
|
||||
if (value == PCI_BAR_RANGE_MASK) {
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
lo |= soft_bar_flag[n];
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else if (value & 0x01) {
|
||||
/* NATIVE reg */
|
||||
hi = 0x0000f001;
|
||||
lo &= bar_space_range[n];
|
||||
_wrmsr(divil_msr_reg[n], hi, lo);
|
||||
|
||||
/* RCONFx is 4bytes in units for I/O space */
|
||||
hi = ((value & 0x000ffffc) << 12) |
|
||||
((bar_space_len[n] - 4) << 12) | 0x01;
|
||||
lo = ((value & 0x000ffffc) << 12) | 0x01;
|
||||
_wrmsr(sb_msr_reg[n], hi, lo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BAR read: read the n BAR
|
||||
*/
|
||||
|
||||
u32 pci_isa_read_bar(int n)
|
||||
{
|
||||
u32 conf_data = 0;
|
||||
u32 hi, lo;
|
||||
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
if (lo & soft_bar_flag[n]) {
|
||||
conf_data = bar_space_range[n] | PCI_BASE_ADDRESS_SPACE_IO;
|
||||
lo &= ~soft_bar_flag[n];
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else {
|
||||
_rdmsr(divil_msr_reg[n], &hi, &lo);
|
||||
conf_data = lo & bar_space_range[n];
|
||||
conf_data |= 0x01;
|
||||
conf_data &= ~0x02;
|
||||
}
|
||||
return conf_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* isa_write: ISA write transfer
|
||||
*
|
||||
* We assume that this is not a bus master transfer.
|
||||
*/
|
||||
void pci_isa_write_reg(int reg, u32 value)
|
||||
{
|
||||
u32 hi = 0, lo = value;
|
||||
u32 temp;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_COMMAND:
|
||||
if (value & PCI_COMMAND_IO)
|
||||
divil_lbar_enable();
|
||||
else
|
||||
divil_lbar_disable();
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
temp = lo & 0x0000ffff;
|
||||
if ((value & PCI_STATUS_SIG_TARGET_ABORT) &&
|
||||
(lo & SB_TAS_ERR_EN))
|
||||
temp |= SB_TAS_ERR_FLAG;
|
||||
|
||||
if ((value & PCI_STATUS_REC_TARGET_ABORT) &&
|
||||
(lo & SB_TAR_ERR_EN))
|
||||
temp |= SB_TAR_ERR_FLAG;
|
||||
|
||||
if ((value & PCI_STATUS_REC_MASTER_ABORT)
|
||||
&& (lo & SB_MAR_ERR_EN))
|
||||
temp |= SB_MAR_ERR_FLAG;
|
||||
|
||||
if ((value & PCI_STATUS_DETECTED_PARITY)
|
||||
&& (lo & SB_PARE_ERR_EN))
|
||||
temp |= SB_PARE_ERR_FLAG;
|
||||
|
||||
lo = temp;
|
||||
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
|
||||
break;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
value &= 0x0000ff00;
|
||||
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
|
||||
hi &= 0xffffff00;
|
||||
hi |= (value >> 8);
|
||||
_wrmsr(SB_MSR_REG(SB_CTRL), hi, lo);
|
||||
break;
|
||||
case PCI_BAR0_REG:
|
||||
pci_isa_write_bar(0, value);
|
||||
break;
|
||||
case PCI_BAR1_REG:
|
||||
pci_isa_write_bar(1, value);
|
||||
break;
|
||||
case PCI_BAR2_REG:
|
||||
pci_isa_write_bar(2, value);
|
||||
break;
|
||||
case PCI_BAR3_REG:
|
||||
pci_isa_write_bar(3, value);
|
||||
break;
|
||||
case PCI_BAR4_REG:
|
||||
pci_isa_write_bar(4, value);
|
||||
break;
|
||||
case PCI_BAR5_REG:
|
||||
pci_isa_write_bar(5, value);
|
||||
break;
|
||||
case PCI_UART1_INT_REG:
|
||||
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
|
||||
/* disable uart1 interrupt in PIC */
|
||||
lo &= ~(0xf << 24);
|
||||
if (value) /* enable uart1 interrupt in PIC */
|
||||
lo |= (CS5536_UART1_INTR << 24);
|
||||
_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
|
||||
break;
|
||||
case PCI_UART2_INT_REG:
|
||||
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), &hi, &lo);
|
||||
/* disable uart2 interrupt in PIC */
|
||||
lo &= ~(0xf << 28);
|
||||
if (value) /* enable uart2 interrupt in PIC */
|
||||
lo |= (CS5536_UART2_INTR << 28);
|
||||
_wrmsr(DIVIL_MSR_REG(PIC_YSEL_HIGH), hi, lo);
|
||||
break;
|
||||
case PCI_ISA_FIXUP_REG:
|
||||
if (value) {
|
||||
/* enable the TARGET ABORT/MASTER ABORT etc. */
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
lo |= 0x00000063;
|
||||
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
|
||||
}
|
||||
|
||||
default:
|
||||
/* ALL OTHER PCI CONFIG SPACE HEADER IS NOT IMPLEMENTED. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* isa_read: ISA read transfers
|
||||
*
|
||||
* We assume that this is not a bus master transfer.
|
||||
*/
|
||||
u32 pci_isa_read_reg(int reg)
|
||||
{
|
||||
u32 conf_data = 0;
|
||||
u32 hi, lo;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_ISA_DEVICE_ID, CS5536_VENDOR_ID);
|
||||
break;
|
||||
case PCI_COMMAND:
|
||||
/* we just check the first LBAR for the IO enable bit, */
|
||||
/* maybe we should changed later. */
|
||||
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), &hi, &lo);
|
||||
if (hi & 0x01)
|
||||
conf_data |= PCI_COMMAND_IO;
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
conf_data |= PCI_STATUS_66MHZ;
|
||||
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
|
||||
conf_data |= PCI_STATUS_FAST_BACK;
|
||||
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
if (lo & SB_TAS_ERR_FLAG)
|
||||
conf_data |= PCI_STATUS_SIG_TARGET_ABORT;
|
||||
if (lo & SB_TAR_ERR_FLAG)
|
||||
conf_data |= PCI_STATUS_REC_TARGET_ABORT;
|
||||
if (lo & SB_MAR_ERR_FLAG)
|
||||
conf_data |= PCI_STATUS_REC_MASTER_ABORT;
|
||||
if (lo & SB_PARE_ERR_FLAG)
|
||||
conf_data |= PCI_STATUS_DETECTED_PARITY;
|
||||
break;
|
||||
case PCI_CLASS_REVISION:
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_CHIP_REV_ID), &hi, &lo);
|
||||
conf_data = lo & 0x000000ff;
|
||||
conf_data |= (CS5536_ISA_CLASS_CODE << 8);
|
||||
break;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
_rdmsr(SB_MSR_REG(SB_CTRL), &hi, &lo);
|
||||
hi &= 0x000000f8;
|
||||
conf_data = CFG_PCI_CACHE_LINE_SIZE(PCI_BRIDGE_HEADER_TYPE, hi);
|
||||
break;
|
||||
/*
|
||||
* we only use the LBAR of DIVIL, no RCONF used.
|
||||
* all of them are IO space.
|
||||
*/
|
||||
case PCI_BAR0_REG:
|
||||
return pci_isa_read_bar(0);
|
||||
break;
|
||||
case PCI_BAR1_REG:
|
||||
return pci_isa_read_bar(1);
|
||||
break;
|
||||
case PCI_BAR2_REG:
|
||||
return pci_isa_read_bar(2);
|
||||
break;
|
||||
case PCI_BAR3_REG:
|
||||
break;
|
||||
case PCI_BAR4_REG:
|
||||
return pci_isa_read_bar(4);
|
||||
break;
|
||||
case PCI_BAR5_REG:
|
||||
return pci_isa_read_bar(5);
|
||||
break;
|
||||
case PCI_CARDBUS_CIS:
|
||||
conf_data = PCI_CARDBUS_CIS_POINTER;
|
||||
break;
|
||||
case PCI_SUBSYSTEM_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_ISA_SUB_ID, CS5536_SUB_VENDOR_ID);
|
||||
break;
|
||||
case PCI_ROM_ADDRESS:
|
||||
conf_data = PCI_EXPANSION_ROM_BAR;
|
||||
break;
|
||||
case PCI_CAPABILITY_LIST:
|
||||
conf_data = PCI_CAPLIST_POINTER;
|
||||
break;
|
||||
case PCI_INTERRUPT_LINE:
|
||||
/* no interrupt used here */
|
||||
conf_data = CFG_PCI_INTERRUPT_LINE(0x00, 0x00);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return conf_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* The mfgpt timer interrupt is running early, so we must keep the south bridge
|
||||
* mmio always enabled. Otherwise we may race with the PCI configuration which
|
||||
* may temporarily disable it. When that happens and the timer interrupt fires,
|
||||
* we are not able to clear it and the system will hang.
|
||||
*/
|
||||
static void cs5536_isa_mmio_always_on(struct pci_dev *dev)
|
||||
{
|
||||
dev->mmio_always_on = 1;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
|
||||
PCI_CLASS_BRIDGE_ISA, 8, cs5536_isa_mmio_always_on);
|
||||
213
arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
Normal file
213
arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* CS5536 General timer functions
|
||||
*
|
||||
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
|
||||
* Author: Yanhua, yanh@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote Inc.
|
||||
* Author: Wu zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* Reference: AMD Geode(TM) CS5536 Companion Device Data Book
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clockchips.h>
|
||||
|
||||
#include <asm/time.h>
|
||||
|
||||
#include <cs5536/cs5536_mfgpt.h>
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(mfgpt_lock);
|
||||
|
||||
static u32 mfgpt_base;
|
||||
|
||||
/*
|
||||
* Initialize the MFGPT timer.
|
||||
*
|
||||
* This is also called after resume to bring the MFGPT into operation again.
|
||||
*/
|
||||
|
||||
/* disable counter */
|
||||
void disable_mfgpt0_counter(void)
|
||||
{
|
||||
outw(inw(MFGPT0_SETUP) & 0x7fff, MFGPT0_SETUP);
|
||||
}
|
||||
EXPORT_SYMBOL(disable_mfgpt0_counter);
|
||||
|
||||
/* enable counter, comparator2 to event mode, 14.318MHz clock */
|
||||
void enable_mfgpt0_counter(void)
|
||||
{
|
||||
outw(0xe310, MFGPT0_SETUP);
|
||||
}
|
||||
EXPORT_SYMBOL(enable_mfgpt0_counter);
|
||||
|
||||
static void init_mfgpt_timer(enum clock_event_mode mode,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
raw_spin_lock(&mfgpt_lock);
|
||||
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */
|
||||
outw(0, MFGPT0_CNT); /* set counter to 0 */
|
||||
enable_mfgpt0_counter();
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
|
||||
evt->mode == CLOCK_EVT_MODE_ONESHOT)
|
||||
disable_mfgpt0_counter();
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
/* The oneshot mode have very high deviation, Not use it! */
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_MODE_RESUME:
|
||||
/* Nothing to do here */
|
||||
break;
|
||||
}
|
||||
raw_spin_unlock(&mfgpt_lock);
|
||||
}
|
||||
|
||||
static struct clock_event_device mfgpt_clockevent = {
|
||||
.name = "mfgpt",
|
||||
.features = CLOCK_EVT_FEAT_PERIODIC,
|
||||
.set_mode = init_mfgpt_timer,
|
||||
.irq = CS5536_MFGPT_INTR,
|
||||
};
|
||||
|
||||
static irqreturn_t timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
u32 basehi;
|
||||
|
||||
/*
|
||||
* get MFGPT base address
|
||||
*
|
||||
* NOTE: do not remove me, it's need for the value of mfgpt_base is
|
||||
* variable
|
||||
*/
|
||||
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
|
||||
|
||||
/* ack */
|
||||
outw(inw(MFGPT0_SETUP) | 0x4000, MFGPT0_SETUP);
|
||||
|
||||
mfgpt_clockevent.event_handler(&mfgpt_clockevent);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irqaction irq5 = {
|
||||
.handler = timer_interrupt,
|
||||
.flags = IRQF_NOBALANCING | IRQF_TIMER,
|
||||
.name = "timer"
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the conversion factor and the min/max deltas of the clock event
|
||||
* structure and register the clock event source with the framework.
|
||||
*/
|
||||
void __init setup_mfgpt0_timer(void)
|
||||
{
|
||||
u32 basehi;
|
||||
struct clock_event_device *cd = &mfgpt_clockevent;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
cd->cpumask = cpumask_of(cpu);
|
||||
clockevent_set_clock(cd, MFGPT_TICK_RATE);
|
||||
cd->max_delta_ns = clockevent_delta2ns(0xffff, cd);
|
||||
cd->min_delta_ns = clockevent_delta2ns(0xf, cd);
|
||||
|
||||
/* Enable MFGPT0 Comparator 2 Output to the Interrupt Mapper */
|
||||
_wrmsr(DIVIL_MSR_REG(MFGPT_IRQ), 0, 0x100);
|
||||
|
||||
/* Enable Interrupt Gate 5 */
|
||||
_wrmsr(DIVIL_MSR_REG(PIC_ZSEL_LOW), 0, 0x50000);
|
||||
|
||||
/* get MFGPT base address */
|
||||
_rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_MFGPT), &basehi, &mfgpt_base);
|
||||
|
||||
clockevents_register_device(cd);
|
||||
|
||||
setup_irq(CS5536_MFGPT_INTR, &irq5);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since the MFGPT overflows every tick, its not very useful
|
||||
* to just read by itself. So use jiffies to emulate a free
|
||||
* running counter:
|
||||
*/
|
||||
static cycle_t mfgpt_read(struct clocksource *cs)
|
||||
{
|
||||
unsigned long flags;
|
||||
int count;
|
||||
u32 jifs;
|
||||
static int old_count;
|
||||
static u32 old_jifs;
|
||||
|
||||
raw_spin_lock_irqsave(&mfgpt_lock, flags);
|
||||
/*
|
||||
* Although our caller may have the read side of xtime_lock,
|
||||
* this is now a seqlock, and we are cheating in this routine
|
||||
* by having side effects on state that we cannot undo if
|
||||
* there is a collision on the seqlock and our caller has to
|
||||
* retry. (Namely, old_jifs and old_count.) So we must treat
|
||||
* jiffies as volatile despite the lock. We read jiffies
|
||||
* before latching the timer count to guarantee that although
|
||||
* the jiffies value might be older than the count (that is,
|
||||
* the counter may underflow between the last point where
|
||||
* jiffies was incremented and the point where we latch the
|
||||
* count), it cannot be newer.
|
||||
*/
|
||||
jifs = jiffies;
|
||||
/* read the count */
|
||||
count = inw(MFGPT0_CNT);
|
||||
|
||||
/*
|
||||
* It's possible for count to appear to go the wrong way for this
|
||||
* reason:
|
||||
*
|
||||
* The timer counter underflows, but we haven't handled the resulting
|
||||
* interrupt and incremented jiffies yet.
|
||||
*
|
||||
* Previous attempts to handle these cases intelligently were buggy, so
|
||||
* we just do the simple thing now.
|
||||
*/
|
||||
if (count < old_count && jifs == old_jifs)
|
||||
count = old_count;
|
||||
|
||||
old_count = count;
|
||||
old_jifs = jifs;
|
||||
|
||||
raw_spin_unlock_irqrestore(&mfgpt_lock, flags);
|
||||
|
||||
return (cycle_t) (jifs * COMPARE) + count;
|
||||
}
|
||||
|
||||
static struct clocksource clocksource_mfgpt = {
|
||||
.name = "mfgpt",
|
||||
.rating = 120, /* Functional for real use, but not desired */
|
||||
.read = mfgpt_read,
|
||||
.mask = CLOCKSOURCE_MASK(32),
|
||||
};
|
||||
|
||||
int __init init_mfgpt_clocksource(void)
|
||||
{
|
||||
if (num_possible_cpus() > 1) /* MFGPT does not scale! */
|
||||
return 0;
|
||||
|
||||
return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
|
||||
}
|
||||
|
||||
arch_initcall(init_mfgpt_clocksource);
|
||||
149
arch/mips/loongson/common/cs5536/cs5536_ohci.c
Normal file
149
arch/mips/loongson/common/cs5536/cs5536_ohci.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* the OHCI Virtual Support Module of AMD CS5536
|
||||
*
|
||||
* Copyright (C) 2007 Lemote, Inc.
|
||||
* Author : jlliu, liujl@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <cs5536/cs5536.h>
|
||||
#include <cs5536/cs5536_pci.h>
|
||||
|
||||
void pci_ohci_write_reg(int reg, u32 value)
|
||||
{
|
||||
u32 hi = 0, lo = value;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_COMMAND:
|
||||
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
|
||||
if (value & PCI_COMMAND_MASTER)
|
||||
hi |= PCI_COMMAND_MASTER;
|
||||
else
|
||||
hi &= ~PCI_COMMAND_MASTER;
|
||||
|
||||
if (value & PCI_COMMAND_MEMORY)
|
||||
hi |= PCI_COMMAND_MEMORY;
|
||||
else
|
||||
hi &= ~PCI_COMMAND_MEMORY;
|
||||
_wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
if (value & PCI_STATUS_PARITY) {
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
if (lo & SB_PARE_ERR_FLAG) {
|
||||
lo = (lo & 0x0000ffff) | SB_PARE_ERR_FLAG;
|
||||
_wrmsr(SB_MSR_REG(SB_ERROR), hi, lo);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PCI_BAR0_REG:
|
||||
if (value == PCI_BAR_RANGE_MASK) {
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
lo |= SOFT_BAR_OHCI_FLAG;
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else if ((value & 0x01) == 0x00) {
|
||||
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
|
||||
lo = value;
|
||||
_wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
|
||||
|
||||
value &= 0xfffffff0;
|
||||
hi = 0x40000000 | ((value & 0xff000000) >> 24);
|
||||
lo = 0x000fffff | ((value & 0x00fff000) << 8);
|
||||
_wrmsr(GLIU_MSR_REG(GLIU_P2D_BM3), hi, lo);
|
||||
}
|
||||
break;
|
||||
case PCI_OHCI_INT_REG:
|
||||
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
|
||||
lo &= ~(0xf << PIC_YSEL_LOW_USB_SHIFT);
|
||||
if (value) /* enable all the usb interrupt in PIC */
|
||||
lo |= (CS5536_USB_INTR << PIC_YSEL_LOW_USB_SHIFT);
|
||||
_wrmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), hi, lo);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 pci_ohci_read_reg(int reg)
|
||||
{
|
||||
u32 conf_data = 0;
|
||||
u32 hi, lo;
|
||||
|
||||
switch (reg) {
|
||||
case PCI_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_OHCI_DEVICE_ID, CS5536_VENDOR_ID);
|
||||
break;
|
||||
case PCI_COMMAND:
|
||||
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
|
||||
if (hi & PCI_COMMAND_MASTER)
|
||||
conf_data |= PCI_COMMAND_MASTER;
|
||||
if (hi & PCI_COMMAND_MEMORY)
|
||||
conf_data |= PCI_COMMAND_MEMORY;
|
||||
break;
|
||||
case PCI_STATUS:
|
||||
conf_data |= PCI_STATUS_66MHZ;
|
||||
conf_data |= PCI_STATUS_FAST_BACK;
|
||||
_rdmsr(SB_MSR_REG(SB_ERROR), &hi, &lo);
|
||||
if (lo & SB_PARE_ERR_FLAG)
|
||||
conf_data |= PCI_STATUS_PARITY;
|
||||
conf_data |= PCI_STATUS_DEVSEL_MEDIUM;
|
||||
break;
|
||||
case PCI_CLASS_REVISION:
|
||||
_rdmsr(USB_MSR_REG(USB_CAP), &hi, &lo);
|
||||
conf_data = lo & 0x000000ff;
|
||||
conf_data |= (CS5536_OHCI_CLASS_CODE << 8);
|
||||
break;
|
||||
case PCI_CACHE_LINE_SIZE:
|
||||
conf_data =
|
||||
CFG_PCI_CACHE_LINE_SIZE(PCI_NORMAL_HEADER_TYPE,
|
||||
PCI_NORMAL_LATENCY_TIMER);
|
||||
break;
|
||||
case PCI_BAR0_REG:
|
||||
_rdmsr(GLCP_MSR_REG(GLCP_SOFT_COM), &hi, &lo);
|
||||
if (lo & SOFT_BAR_OHCI_FLAG) {
|
||||
conf_data = CS5536_OHCI_RANGE |
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY;
|
||||
lo &= ~SOFT_BAR_OHCI_FLAG;
|
||||
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
|
||||
} else {
|
||||
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
|
||||
conf_data = lo & 0xffffff00;
|
||||
conf_data &= ~0x0000000f; /* 32bit mem */
|
||||
}
|
||||
break;
|
||||
case PCI_CARDBUS_CIS:
|
||||
conf_data = PCI_CARDBUS_CIS_POINTER;
|
||||
break;
|
||||
case PCI_SUBSYSTEM_VENDOR_ID:
|
||||
conf_data =
|
||||
CFG_PCI_VENDOR_ID(CS5536_OHCI_SUB_ID, CS5536_SUB_VENDOR_ID);
|
||||
break;
|
||||
case PCI_ROM_ADDRESS:
|
||||
conf_data = PCI_EXPANSION_ROM_BAR;
|
||||
break;
|
||||
case PCI_CAPABILITY_LIST:
|
||||
conf_data = PCI_CAPLIST_USB_POINTER;
|
||||
break;
|
||||
case PCI_INTERRUPT_LINE:
|
||||
conf_data =
|
||||
CFG_PCI_INTERRUPT_LINE(PCI_DEFAULT_PIN, CS5536_USB_INTR);
|
||||
break;
|
||||
case PCI_OHCI_INT_REG:
|
||||
_rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo);
|
||||
if ((lo & 0x00000f00) == CS5536_USB_INTR)
|
||||
conf_data = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return conf_data;
|
||||
}
|
||||
87
arch/mips/loongson/common/cs5536/cs5536_pci.c
Normal file
87
arch/mips/loongson/common/cs5536/cs5536_pci.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* read/write operation to the PCI config space of CS5536
|
||||
*
|
||||
* Copyright (C) 2007 Lemote, Inc.
|
||||
* Author : jlliu, liujl@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* the Virtual Support Module(VSM) for virtulizing the PCI
|
||||
* configure space are defined in cs5536_modulename.c respectively,
|
||||
*
|
||||
* after this virtulizing, user can access the PCI configure space
|
||||
* directly as a normal multi-function PCI device which follows
|
||||
* the PCI-2.2 spec.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <cs5536/cs5536_vsm.h>
|
||||
|
||||
enum {
|
||||
CS5536_FUNC_START = -1,
|
||||
CS5536_ISA_FUNC,
|
||||
reserved_func,
|
||||
CS5536_IDE_FUNC,
|
||||
CS5536_ACC_FUNC,
|
||||
CS5536_OHCI_FUNC,
|
||||
CS5536_EHCI_FUNC,
|
||||
CS5536_FUNC_END,
|
||||
};
|
||||
|
||||
static const cs5536_pci_vsm_write vsm_conf_write[] = {
|
||||
[CS5536_ISA_FUNC] pci_isa_write_reg,
|
||||
[reserved_func] NULL,
|
||||
[CS5536_IDE_FUNC] pci_ide_write_reg,
|
||||
[CS5536_ACC_FUNC] pci_acc_write_reg,
|
||||
[CS5536_OHCI_FUNC] pci_ohci_write_reg,
|
||||
[CS5536_EHCI_FUNC] pci_ehci_write_reg,
|
||||
};
|
||||
|
||||
static const cs5536_pci_vsm_read vsm_conf_read[] = {
|
||||
[CS5536_ISA_FUNC] pci_isa_read_reg,
|
||||
[reserved_func] NULL,
|
||||
[CS5536_IDE_FUNC] pci_ide_read_reg,
|
||||
[CS5536_ACC_FUNC] pci_acc_read_reg,
|
||||
[CS5536_OHCI_FUNC] pci_ohci_read_reg,
|
||||
[CS5536_EHCI_FUNC] pci_ehci_read_reg,
|
||||
};
|
||||
|
||||
/*
|
||||
* write to PCI config space and transfer it to MSR write.
|
||||
*/
|
||||
void cs5536_pci_conf_write4(int function, int reg, u32 value)
|
||||
{
|
||||
if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END))
|
||||
return;
|
||||
if ((reg < 0) || (reg > 0x100) || ((reg & 0x03) != 0))
|
||||
return;
|
||||
|
||||
if (vsm_conf_write[function] != NULL)
|
||||
vsm_conf_write[function](reg, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* read PCI config space and transfer it to MSR access.
|
||||
*/
|
||||
u32 cs5536_pci_conf_read4(int function, int reg)
|
||||
{
|
||||
u32 data = 0;
|
||||
|
||||
if ((function <= CS5536_FUNC_START) || (function >= CS5536_FUNC_END))
|
||||
return 0;
|
||||
if ((reg < 0) || ((reg & 0x03) != 0))
|
||||
return 0;
|
||||
if (reg > 0x100)
|
||||
return 0xffffffff;
|
||||
|
||||
if (vsm_conf_read[function] != NULL)
|
||||
data = vsm_conf_read[function](reg);
|
||||
|
||||
return data;
|
||||
}
|
||||
136
arch/mips/loongson/common/dma-swiotlb.c
Normal file
136
arch/mips/loongson/common/dma-swiotlb.c
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/swiotlb.h>
|
||||
#include <linux/bootmem.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <boot_param.h>
|
||||
#include <dma-coherence.h>
|
||||
|
||||
static void *loongson_dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
|
||||
return ret;
|
||||
|
||||
/* ignore region specifiers */
|
||||
gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
|
||||
|
||||
#ifdef CONFIG_ISA
|
||||
if (dev == NULL)
|
||||
gfp |= __GFP_DMA;
|
||||
else
|
||||
#endif
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
if (dev->coherent_dma_mask < DMA_BIT_MASK(32))
|
||||
gfp |= __GFP_DMA;
|
||||
else
|
||||
#endif
|
||||
#ifdef CONFIG_ZONE_DMA32
|
||||
if (dev->coherent_dma_mask < DMA_BIT_MASK(40))
|
||||
gfp |= __GFP_DMA32;
|
||||
else
|
||||
#endif
|
||||
;
|
||||
gfp |= __GFP_NORETRY;
|
||||
|
||||
ret = swiotlb_alloc_coherent(dev, size, dma_handle, gfp);
|
||||
mb();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void loongson_dma_free_coherent(struct device *dev, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs)
|
||||
{
|
||||
int order = get_order(size);
|
||||
|
||||
if (dma_release_from_coherent(dev, order, vaddr))
|
||||
return;
|
||||
|
||||
swiotlb_free_coherent(dev, size, vaddr, dma_handle);
|
||||
}
|
||||
|
||||
static dma_addr_t loongson_dma_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction dir,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
dma_addr_t daddr = swiotlb_map_page(dev, page, offset, size,
|
||||
dir, attrs);
|
||||
mb();
|
||||
return daddr;
|
||||
}
|
||||
|
||||
static int loongson_dma_map_sg(struct device *dev, struct scatterlist *sg,
|
||||
int nents, enum dma_data_direction dir,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
int r = swiotlb_map_sg_attrs(dev, sg, nents, dir, NULL);
|
||||
mb();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void loongson_dma_sync_single_for_device(struct device *dev,
|
||||
dma_addr_t dma_handle, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
swiotlb_sync_single_for_device(dev, dma_handle, size, dir);
|
||||
mb();
|
||||
}
|
||||
|
||||
static void loongson_dma_sync_sg_for_device(struct device *dev,
|
||||
struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
swiotlb_sync_sg_for_device(dev, sg, nents, dir);
|
||||
mb();
|
||||
}
|
||||
|
||||
static int loongson_dma_set_mask(struct device *dev, u64 mask)
|
||||
{
|
||||
if (mask > DMA_BIT_MASK(loongson_sysconf.dma_mask_bits)) {
|
||||
*dev->dma_mask = DMA_BIT_MASK(loongson_sysconf.dma_mask_bits);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*dev->dma_mask = mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
|
||||
{
|
||||
return paddr;
|
||||
}
|
||||
|
||||
phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
|
||||
{
|
||||
return daddr;
|
||||
}
|
||||
|
||||
static struct dma_map_ops loongson_dma_map_ops = {
|
||||
.alloc = loongson_dma_alloc_coherent,
|
||||
.free = loongson_dma_free_coherent,
|
||||
.map_page = loongson_dma_map_page,
|
||||
.unmap_page = swiotlb_unmap_page,
|
||||
.map_sg = loongson_dma_map_sg,
|
||||
.unmap_sg = swiotlb_unmap_sg_attrs,
|
||||
.sync_single_for_cpu = swiotlb_sync_single_for_cpu,
|
||||
.sync_single_for_device = loongson_dma_sync_single_for_device,
|
||||
.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
|
||||
.sync_sg_for_device = loongson_dma_sync_sg_for_device,
|
||||
.mapping_error = swiotlb_dma_mapping_error,
|
||||
.dma_supported = swiotlb_dma_supported,
|
||||
.set_dma_mask = loongson_dma_set_mask
|
||||
};
|
||||
|
||||
void __init plat_swiotlb_setup(void)
|
||||
{
|
||||
swiotlb_init(1);
|
||||
mips_dma_map_ops = &loongson_dma_map_ops;
|
||||
}
|
||||
41
arch/mips/loongson/common/early_printk.c
Normal file
41
arch/mips/loongson/common/early_printk.c
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* early printk support
|
||||
*
|
||||
* Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca>
|
||||
* Copyright (c) 2009 Lemote Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#include <loongson.h>
|
||||
|
||||
#define PORT(base, offset) (u8 *)(base + offset)
|
||||
|
||||
static inline unsigned int serial_in(unsigned char *base, int offset)
|
||||
{
|
||||
return readb(PORT(base, offset));
|
||||
}
|
||||
|
||||
static inline void serial_out(unsigned char *base, int offset, int value)
|
||||
{
|
||||
writeb(value, PORT(base, offset));
|
||||
}
|
||||
|
||||
void prom_putchar(char c)
|
||||
{
|
||||
int timeout;
|
||||
unsigned char *uart_base;
|
||||
|
||||
uart_base = (unsigned char *)_loongson_uart_base;
|
||||
timeout = 1024;
|
||||
|
||||
while (((serial_in(uart_base, UART_LSR) & UART_LSR_THRE) == 0) &&
|
||||
(timeout-- > 0))
|
||||
;
|
||||
|
||||
serial_out(uart_base, UART_TX, c);
|
||||
}
|
||||
167
arch/mips/loongson/common/env.c
Normal file
167
arch/mips/loongson/common/env.c
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Based on Ocelot Linux port, which is
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
* Author: jsun@mvista.com or jsun@junsun.net
|
||||
*
|
||||
* Copyright 2003 ICT CAS
|
||||
* Author: Michael Guo <guoyi@ict.ac.cn>
|
||||
*
|
||||
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
|
||||
* Author: Fuxin Zhang, zhangfx@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <loongson.h>
|
||||
#include <boot_param.h>
|
||||
|
||||
u32 cpu_clock_freq;
|
||||
EXPORT_SYMBOL(cpu_clock_freq);
|
||||
struct efi_memory_map_loongson *loongson_memmap;
|
||||
struct loongson_system_configuration loongson_sysconf;
|
||||
|
||||
u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
|
||||
u64 loongson_freqctrl[MAX_PACKAGES];
|
||||
|
||||
unsigned long long smp_group[4];
|
||||
int cpuhotplug_workaround = 0;
|
||||
|
||||
#define parse_even_earlier(res, option, p) \
|
||||
do { \
|
||||
unsigned int tmp __maybe_unused; \
|
||||
\
|
||||
if (strncmp(option, (char *)p, strlen(option)) == 0) \
|
||||
tmp = kstrtou32((char *)p + strlen(option"="), 10, &res); \
|
||||
} while (0)
|
||||
|
||||
void __init prom_init_env(void)
|
||||
{
|
||||
/* pmon passes arguments in 32bit pointers */
|
||||
unsigned int processor_id;
|
||||
|
||||
#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
|
||||
int *_prom_envp;
|
||||
long l;
|
||||
|
||||
/* firmware arguments are initialized in head.S */
|
||||
_prom_envp = (int *)fw_arg2;
|
||||
|
||||
l = (long)*_prom_envp;
|
||||
while (l != 0) {
|
||||
parse_even_earlier(cpu_clock_freq, "cpuclock", l);
|
||||
parse_even_earlier(memsize, "memsize", l);
|
||||
parse_even_earlier(highmemsize, "highmemsize", l);
|
||||
_prom_envp++;
|
||||
l = (long)*_prom_envp;
|
||||
}
|
||||
if (memsize == 0)
|
||||
memsize = 256;
|
||||
pr_info("memsize=%u, highmemsize=%u\n", memsize, highmemsize);
|
||||
#else
|
||||
struct boot_params *boot_p;
|
||||
struct loongson_params *loongson_p;
|
||||
struct efi_cpuinfo_loongson *ecpu;
|
||||
struct irq_source_routing_table *eirq_source;
|
||||
|
||||
/* firmware arguments are initialized in head.S */
|
||||
boot_p = (struct boot_params *)fw_arg2;
|
||||
loongson_p = &(boot_p->efi.smbios.lp);
|
||||
|
||||
ecpu = (struct efi_cpuinfo_loongson *)
|
||||
((u64)loongson_p + loongson_p->cpu_offset);
|
||||
eirq_source = (struct irq_source_routing_table *)
|
||||
((u64)loongson_p + loongson_p->irq_offset);
|
||||
loongson_memmap = (struct efi_memory_map_loongson *)
|
||||
((u64)loongson_p + loongson_p->memory_offset);
|
||||
|
||||
cpu_clock_freq = ecpu->cpu_clock_freq;
|
||||
loongson_sysconf.cputype = ecpu->cputype;
|
||||
if (ecpu->cputype == Loongson_3A) {
|
||||
loongson_sysconf.cores_per_node = 4;
|
||||
loongson_sysconf.cores_per_package = 4;
|
||||
smp_group[0] = 0x900000003ff01000;
|
||||
smp_group[1] = 0x900010003ff01000;
|
||||
smp_group[2] = 0x900020003ff01000;
|
||||
smp_group[3] = 0x900030003ff01000;
|
||||
loongson_chipcfg[0] = 0x900000001fe00180;
|
||||
loongson_chipcfg[1] = 0x900010001fe00180;
|
||||
loongson_chipcfg[2] = 0x900020001fe00180;
|
||||
loongson_chipcfg[3] = 0x900030001fe00180;
|
||||
loongson_sysconf.ht_control_base = 0x90000EFDFB000000;
|
||||
} else if (ecpu->cputype == Loongson_3B) {
|
||||
loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */
|
||||
loongson_sysconf.cores_per_package = 8;
|
||||
smp_group[0] = 0x900000003ff01000;
|
||||
smp_group[1] = 0x900010003ff05000;
|
||||
smp_group[2] = 0x900020003ff09000;
|
||||
smp_group[3] = 0x900030003ff0d000;
|
||||
loongson_chipcfg[0] = 0x900000001fe00180;
|
||||
loongson_chipcfg[1] = 0x900020001fe00180;
|
||||
loongson_chipcfg[2] = 0x900040001fe00180;
|
||||
loongson_chipcfg[3] = 0x900060001fe00180;
|
||||
loongson_freqctrl[0] = 0x900000001fe001d0;
|
||||
loongson_freqctrl[1] = 0x900020001fe001d0;
|
||||
loongson_freqctrl[2] = 0x900040001fe001d0;
|
||||
loongson_freqctrl[3] = 0x900060001fe001d0;
|
||||
loongson_sysconf.ht_control_base = 0x90001EFDFB000000;
|
||||
cpuhotplug_workaround = 1;
|
||||
} else {
|
||||
loongson_sysconf.cores_per_node = 1;
|
||||
loongson_sysconf.cores_per_package = 1;
|
||||
loongson_chipcfg[0] = 0x900000001fe00180;
|
||||
}
|
||||
|
||||
loongson_sysconf.nr_cpus = ecpu->nr_cpus;
|
||||
if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0)
|
||||
loongson_sysconf.nr_cpus = NR_CPUS;
|
||||
loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus +
|
||||
loongson_sysconf.cores_per_node - 1) /
|
||||
loongson_sysconf.cores_per_node;
|
||||
|
||||
loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr;
|
||||
loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr;
|
||||
loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr;
|
||||
loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits;
|
||||
if (loongson_sysconf.dma_mask_bits < 32 ||
|
||||
loongson_sysconf.dma_mask_bits > 64)
|
||||
loongson_sysconf.dma_mask_bits = 32;
|
||||
|
||||
loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm;
|
||||
loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
|
||||
loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend;
|
||||
|
||||
loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios;
|
||||
pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
|
||||
loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
|
||||
loongson_sysconf.vgabios_addr);
|
||||
#endif
|
||||
if (cpu_clock_freq == 0) {
|
||||
processor_id = (¤t_cpu_data)->processor_id;
|
||||
switch (processor_id & PRID_REV_MASK) {
|
||||
case PRID_REV_LOONGSON2E:
|
||||
cpu_clock_freq = 533080000;
|
||||
break;
|
||||
case PRID_REV_LOONGSON2F:
|
||||
cpu_clock_freq = 797000000;
|
||||
break;
|
||||
case PRID_REV_LOONGSON3A:
|
||||
cpu_clock_freq = 900000000;
|
||||
break;
|
||||
case PRID_REV_LOONGSON3B_R1:
|
||||
case PRID_REV_LOONGSON3B_R2:
|
||||
cpu_clock_freq = 1000000000;
|
||||
break;
|
||||
default:
|
||||
cpu_clock_freq = 100000000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pr_info("CpuClock = %u\n", cpu_clock_freq);
|
||||
}
|
||||
139
arch/mips/loongson/common/gpio.c
Normal file
139
arch/mips/loongson/common/gpio.c
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* STLS2F GPIO Support
|
||||
*
|
||||
* Copyright (c) 2008 Richard Liu, STMicroelectronics <richard.liu@st.com>
|
||||
* Copyright (c) 2008-2010 Arnaud Patard <apatard@mandriva.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/types.h>
|
||||
#include <loongson.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#define STLS2F_N_GPIO 4
|
||||
#define STLS2F_GPIO_IN_OFFSET 16
|
||||
|
||||
static DEFINE_SPINLOCK(gpio_lock);
|
||||
|
||||
int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
u32 val;
|
||||
u32 mask;
|
||||
|
||||
if (gpio >= STLS2F_N_GPIO)
|
||||
return __gpio_get_value(gpio);
|
||||
|
||||
mask = 1 << (gpio + STLS2F_GPIO_IN_OFFSET);
|
||||
spin_lock(&gpio_lock);
|
||||
val = LOONGSON_GPIODATA;
|
||||
spin_unlock(&gpio_lock);
|
||||
|
||||
return ((val & mask) != 0);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_get_value);
|
||||
|
||||
void gpio_set_value(unsigned gpio, int state)
|
||||
{
|
||||
u32 val;
|
||||
u32 mask;
|
||||
|
||||
if (gpio >= STLS2F_N_GPIO) {
|
||||
__gpio_set_value(gpio, state);
|
||||
return ;
|
||||
}
|
||||
|
||||
mask = 1 << gpio;
|
||||
|
||||
spin_lock(&gpio_lock);
|
||||
val = LOONGSON_GPIODATA;
|
||||
if (state)
|
||||
val |= mask;
|
||||
else
|
||||
val &= (~mask);
|
||||
LOONGSON_GPIODATA = val;
|
||||
spin_unlock(&gpio_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_set_value);
|
||||
|
||||
int gpio_cansleep(unsigned gpio)
|
||||
{
|
||||
if (gpio < STLS2F_N_GPIO)
|
||||
return 0;
|
||||
else
|
||||
return __gpio_cansleep(gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_cansleep);
|
||||
|
||||
static int ls2f_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
u32 temp;
|
||||
u32 mask;
|
||||
|
||||
if (gpio >= STLS2F_N_GPIO)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&gpio_lock);
|
||||
mask = 1 << gpio;
|
||||
temp = LOONGSON_GPIOIE;
|
||||
temp |= mask;
|
||||
LOONGSON_GPIOIE = temp;
|
||||
spin_unlock(&gpio_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ls2f_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned gpio, int level)
|
||||
{
|
||||
u32 temp;
|
||||
u32 mask;
|
||||
|
||||
if (gpio >= STLS2F_N_GPIO)
|
||||
return -EINVAL;
|
||||
|
||||
gpio_set_value(gpio, level);
|
||||
spin_lock(&gpio_lock);
|
||||
mask = 1 << gpio;
|
||||
temp = LOONGSON_GPIOIE;
|
||||
temp &= (~mask);
|
||||
LOONGSON_GPIOIE = temp;
|
||||
spin_unlock(&gpio_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ls2f_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
return gpio_get_value(gpio);
|
||||
}
|
||||
|
||||
static void ls2f_gpio_set_value(struct gpio_chip *chip,
|
||||
unsigned gpio, int value)
|
||||
{
|
||||
gpio_set_value(gpio, value);
|
||||
}
|
||||
|
||||
static struct gpio_chip ls2f_chip = {
|
||||
.label = "ls2f",
|
||||
.direction_input = ls2f_gpio_direction_input,
|
||||
.get = ls2f_gpio_get_value,
|
||||
.direction_output = ls2f_gpio_direction_output,
|
||||
.set = ls2f_gpio_set_value,
|
||||
.base = 0,
|
||||
.ngpio = STLS2F_N_GPIO,
|
||||
};
|
||||
|
||||
static int __init ls2f_gpio_setup(void)
|
||||
{
|
||||
return gpiochip_add(&ls2f_chip);
|
||||
}
|
||||
arch_initcall(ls2f_gpio_setup);
|
||||
46
arch/mips/loongson/common/init.c
Normal file
46
arch/mips/loongson/common/init.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Lemote Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/bootmem.h>
|
||||
#include <asm/smp-ops.h>
|
||||
|
||||
#include <loongson.h>
|
||||
|
||||
/* Loongson CPU address windows config space base address */
|
||||
unsigned long __maybe_unused _loongson_addrwincfg_base;
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
|
||||
_loongson_addrwincfg_base = (unsigned long)
|
||||
ioremap(LOONGSON_ADDRWINCFG_BASE, LOONGSON_ADDRWINCFG_SIZE);
|
||||
#endif
|
||||
|
||||
prom_init_cmdline();
|
||||
prom_init_env();
|
||||
|
||||
/* init base address of io space */
|
||||
set_io_port_base((unsigned long)
|
||||
ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE));
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
prom_init_numa_memory();
|
||||
#else
|
||||
prom_init_memory();
|
||||
#endif
|
||||
|
||||
/*init the uart base address */
|
||||
prom_init_uart_base();
|
||||
register_smp_ops(&loongson3_smp_ops);
|
||||
}
|
||||
|
||||
void __init prom_free_prom_memory(void)
|
||||
{
|
||||
}
|
||||
67
arch/mips/loongson/common/irq.c
Normal file
67
arch/mips/loongson/common/irq.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
|
||||
* Author: Fuxin Zhang, zhangfx@lemote.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <loongson.h>
|
||||
/*
|
||||
* the first level int-handler will jump here if it is a bonito irq
|
||||
*/
|
||||
void bonito_irqdispatch(void)
|
||||
{
|
||||
u32 int_status;
|
||||
int i;
|
||||
|
||||
/* workaround the IO dma problem: let cpu looping to allow DMA finish */
|
||||
int_status = LOONGSON_INTISR;
|
||||
while (int_status & (1 << 10)) {
|
||||
udelay(1);
|
||||
int_status = LOONGSON_INTISR;
|
||||
}
|
||||
|
||||
/* Get pending sources, masked by current enables */
|
||||
int_status = LOONGSON_INTISR & LOONGSON_INTEN;
|
||||
|
||||
if (int_status) {
|
||||
i = __ffs(int_status);
|
||||
do_IRQ(LOONGSON_IRQ_BASE + i);
|
||||
}
|
||||
}
|
||||
|
||||
asmlinkage void plat_irq_dispatch(void)
|
||||
{
|
||||
unsigned int pending;
|
||||
|
||||
pending = read_c0_cause() & read_c0_status() & ST0_IM;
|
||||
|
||||
/* machine-specific plat_irq_dispatch */
|
||||
mach_irq_dispatch(pending);
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
/*
|
||||
* Clear all of the interrupts while we change the able around a bit.
|
||||
* int-handler is not on bootstrap
|
||||
*/
|
||||
clear_c0_status(ST0_IM | ST0_BEV);
|
||||
|
||||
/* no steer */
|
||||
LOONGSON_INTSTEER = 0;
|
||||
|
||||
/*
|
||||
* Mask out all interrupt by writing "1" to all bit position in
|
||||
* the interrupt reset reg.
|
||||
*/
|
||||
LOONGSON_INTENCLR = ~0;
|
||||
|
||||
/* machine specific irq init */
|
||||
mach_init_irq();
|
||||
}
|
||||
70
arch/mips/loongson/common/machtype.c
Normal file
70
arch/mips/loongson/common/machtype.c
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Lemote Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* Copyright (c) 2009 Zhang Le <r0bertz@gentoo.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
#include <loongson.h>
|
||||
#include <machine.h>
|
||||
|
||||
/* please ensure the length of the machtype string is less than 50 */
|
||||
#define MACHTYPE_LEN 50
|
||||
|
||||
static const char *system_types[] = {
|
||||
[MACH_LOONGSON_UNKNOWN] "unknown loongson machine",
|
||||
[MACH_LEMOTE_FL2E] "lemote-fuloong-2e-box",
|
||||
[MACH_LEMOTE_FL2F] "lemote-fuloong-2f-box",
|
||||
[MACH_LEMOTE_ML2F7] "lemote-mengloong-2f-7inches",
|
||||
[MACH_LEMOTE_YL2F89] "lemote-yeeloong-2f-8.9inches",
|
||||
[MACH_DEXXON_GDIUM2F10] "dexxon-gdium-2f",
|
||||
[MACH_LEMOTE_NAS] "lemote-nas-2f",
|
||||
[MACH_LEMOTE_LL2F] "lemote-lynloong-2f",
|
||||
[MACH_LEMOTE_A1004] "lemote-3a-notebook-a1004",
|
||||
[MACH_LEMOTE_A1101] "lemote-3a-itx-a1101",
|
||||
[MACH_LEMOTE_A1201] "lemote-2gq-notebook-a1201",
|
||||
[MACH_LEMOTE_A1205] "lemote-2gq-aio-a1205",
|
||||
[MACH_LOONGSON_END] NULL,
|
||||
};
|
||||
|
||||
const char *get_system_type(void)
|
||||
{
|
||||
return system_types[mips_machtype];
|
||||
}
|
||||
|
||||
void __weak __init mach_prom_init_machtype(void)
|
||||
{
|
||||
}
|
||||
|
||||
void __init prom_init_machtype(void)
|
||||
{
|
||||
char *p, str[MACHTYPE_LEN + 1];
|
||||
int machtype = MACH_LEMOTE_FL2E;
|
||||
|
||||
mips_machtype = LOONGSON_MACHTYPE;
|
||||
|
||||
p = strstr(arcs_cmdline, "machtype=");
|
||||
if (!p) {
|
||||
mach_prom_init_machtype();
|
||||
return;
|
||||
}
|
||||
p += strlen("machtype=");
|
||||
strncpy(str, p, MACHTYPE_LEN);
|
||||
str[MACHTYPE_LEN] = '\0';
|
||||
p = strstr(str, " ");
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
for (; system_types[machtype]; machtype++)
|
||||
if (strstr(system_types[machtype], str)) {
|
||||
mips_machtype = machtype;
|
||||
break;
|
||||
}
|
||||
}
|
||||
161
arch/mips/loongson/common/mem.c
Normal file
161
arch/mips/loongson/common/mem.c
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
#include <loongson.h>
|
||||
#include <boot_param.h>
|
||||
#include <mem.h>
|
||||
#include <pci.h>
|
||||
|
||||
#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
|
||||
|
||||
u32 memsize, highmemsize;
|
||||
|
||||
void __init prom_init_memory(void)
|
||||
{
|
||||
add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM);
|
||||
|
||||
add_memory_region(memsize << 20, LOONGSON_PCI_MEM_START - (memsize <<
|
||||
20), BOOT_MEM_RESERVED);
|
||||
|
||||
#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
|
||||
{
|
||||
int bit;
|
||||
|
||||
bit = fls(memsize + highmemsize);
|
||||
if (bit != ffs(memsize + highmemsize))
|
||||
bit += 20;
|
||||
else
|
||||
bit = bit + 20 - 1;
|
||||
|
||||
/* set cpu window3 to map CPU to DDR: 2G -> 2G */
|
||||
LOONGSON_ADDRWIN_CPUTODDR(ADDRWIN_WIN3, 0x80000000ul,
|
||||
0x80000000ul, (1 << bit));
|
||||
mmiowb();
|
||||
}
|
||||
#endif /* !CONFIG_CPU_SUPPORTS_ADDRWINCFG */
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
if (highmemsize > 0)
|
||||
add_memory_region(LOONGSON_HIGHMEM_START,
|
||||
highmemsize << 20, BOOT_MEM_RAM);
|
||||
|
||||
add_memory_region(LOONGSON_PCI_MEM_END + 1, LOONGSON_HIGHMEM_START -
|
||||
LOONGSON_PCI_MEM_END - 1, BOOT_MEM_RESERVED);
|
||||
|
||||
#endif /* !CONFIG_64BIT */
|
||||
}
|
||||
|
||||
#else /* CONFIG_LEFI_FIRMWARE_INTERFACE */
|
||||
|
||||
void __init prom_init_memory(void)
|
||||
{
|
||||
int i;
|
||||
u32 node_id;
|
||||
u32 mem_type;
|
||||
|
||||
/* parse memory information */
|
||||
for (i = 0; i < loongson_memmap->nr_map; i++) {
|
||||
node_id = loongson_memmap->map[i].node_id;
|
||||
mem_type = loongson_memmap->map[i].mem_type;
|
||||
|
||||
if (node_id == 0) {
|
||||
switch (mem_type) {
|
||||
case SYSTEM_RAM_LOW:
|
||||
add_memory_region(loongson_memmap->map[i].mem_start,
|
||||
(u64)loongson_memmap->map[i].mem_size << 20,
|
||||
BOOT_MEM_RAM);
|
||||
break;
|
||||
case SYSTEM_RAM_HIGH:
|
||||
add_memory_region(loongson_memmap->map[i].mem_start,
|
||||
(u64)loongson_memmap->map[i].mem_size << 20,
|
||||
BOOT_MEM_RAM);
|
||||
break;
|
||||
case MEM_RESERVED:
|
||||
add_memory_region(loongson_memmap->map[i].mem_start,
|
||||
(u64)loongson_memmap->map[i].mem_size << 20,
|
||||
BOOT_MEM_RESERVED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_LEFI_FIRMWARE_INTERFACE */
|
||||
|
||||
/* override of arch/mips/mm/cache.c: __uncached_access */
|
||||
int __uncached_access(struct file *file, unsigned long addr)
|
||||
{
|
||||
if (file->f_flags & O_DSYNC)
|
||||
return 1;
|
||||
|
||||
return addr >= __pa(high_memory) ||
|
||||
((addr >= LOONGSON_MMIO_MEM_START) &&
|
||||
(addr < LOONGSON_MMIO_MEM_END));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_SUPPORTS_UNCACHED_ACCELERATED
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
#include <asm/current.h>
|
||||
|
||||
static unsigned long uca_start, uca_end;
|
||||
|
||||
pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
|
||||
unsigned long size, pgprot_t vma_prot)
|
||||
{
|
||||
unsigned long offset = pfn << PAGE_SHIFT;
|
||||
unsigned long end = offset + size;
|
||||
|
||||
if (__uncached_access(file, offset)) {
|
||||
if (uca_start && (offset >= uca_start) &&
|
||||
(end <= uca_end))
|
||||
return __pgprot((pgprot_val(vma_prot) &
|
||||
~_CACHE_MASK) |
|
||||
_CACHE_UNCACHED_ACCELERATED);
|
||||
else
|
||||
return pgprot_noncached(vma_prot);
|
||||
}
|
||||
return vma_prot;
|
||||
}
|
||||
|
||||
static int __init find_vga_mem_init(void)
|
||||
{
|
||||
struct pci_dev *dev = 0;
|
||||
struct resource *r;
|
||||
int idx;
|
||||
|
||||
if (uca_start)
|
||||
return 0;
|
||||
|
||||
for_each_pci_dev(dev) {
|
||||
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
|
||||
for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
|
||||
r = &dev->resource[idx];
|
||||
if (!r->start && r->end)
|
||||
continue;
|
||||
if (r->flags & IORESOURCE_IO)
|
||||
continue;
|
||||
if (r->flags & IORESOURCE_MEM) {
|
||||
uca_start = r->start;
|
||||
uca_end = r->end;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
late_initcall(find_vga_mem_init);
|
||||
#endif /* !CONFIG_CPU_SUPPORTS_UNCACHED_ACCELERATED */
|
||||
95
arch/mips/loongson/common/pci.c
Normal file
95
arch/mips/loongson/common/pci.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology
|
||||
* Author: Fuxin Zhang, zhangfx@lemote.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <pci.h>
|
||||
#include <loongson.h>
|
||||
#include <boot_param.h>
|
||||
|
||||
static struct resource loongson_pci_mem_resource = {
|
||||
.name = "pci memory space",
|
||||
.start = LOONGSON_PCI_MEM_START,
|
||||
.end = LOONGSON_PCI_MEM_END,
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
|
||||
static struct resource loongson_pci_io_resource = {
|
||||
.name = "pci io space",
|
||||
.start = LOONGSON_PCI_IO_START,
|
||||
.end = IO_SPACE_LIMIT,
|
||||
.flags = IORESOURCE_IO,
|
||||
};
|
||||
|
||||
static struct pci_controller loongson_pci_controller = {
|
||||
.pci_ops = &loongson_pci_ops,
|
||||
.io_resource = &loongson_pci_io_resource,
|
||||
.mem_resource = &loongson_pci_mem_resource,
|
||||
.mem_offset = 0x00000000UL,
|
||||
.io_offset = 0x00000000UL,
|
||||
};
|
||||
|
||||
static void __init setup_pcimap(void)
|
||||
{
|
||||
/*
|
||||
* local to PCI mapping for CPU accessing PCI space
|
||||
* CPU address space [256M,448M] is window for accessing pci space
|
||||
* we set pcimap_lo[0,1,2] to map it to pci space[0M,64M], [320M,448M]
|
||||
*
|
||||
* pcimap: PCI_MAP2 PCI_Mem_Lo2 PCI_Mem_Lo1 PCI_Mem_Lo0
|
||||
* [<2G] [384M,448M] [320M,384M] [0M,64M]
|
||||
*/
|
||||
LOONGSON_PCIMAP = LOONGSON_PCIMAP_PCIMAP_2 |
|
||||
LOONGSON_PCIMAP_WIN(2, LOONGSON_PCILO2_BASE) |
|
||||
LOONGSON_PCIMAP_WIN(1, LOONGSON_PCILO1_BASE) |
|
||||
LOONGSON_PCIMAP_WIN(0, 0);
|
||||
|
||||
/*
|
||||
* PCI-DMA to local mapping: [2G,2G+256M] -> [0M,256M]
|
||||
*/
|
||||
LOONGSON_PCIBASE0 = 0x80000000ul; /* base: 2G -> mmap: 0M */
|
||||
/* size: 256M, burst transmission, pre-fetch enable, 64bit */
|
||||
LOONGSON_PCI_HIT0_SEL_L = 0xc000000cul;
|
||||
LOONGSON_PCI_HIT0_SEL_H = 0xfffffffful;
|
||||
LOONGSON_PCI_HIT1_SEL_L = 0x00000006ul; /* set this BAR as invalid */
|
||||
LOONGSON_PCI_HIT1_SEL_H = 0x00000000ul;
|
||||
LOONGSON_PCI_HIT2_SEL_L = 0x00000006ul; /* set this BAR as invalid */
|
||||
LOONGSON_PCI_HIT2_SEL_H = 0x00000000ul;
|
||||
|
||||
/* avoid deadlock of PCI reading/writing lock operation */
|
||||
LOONGSON_PCI_ISR4C = 0xd2000001ul;
|
||||
|
||||
/* can not change gnt to break pci transfer when device's gnt not
|
||||
deassert for some broken device */
|
||||
LOONGSON_PXARB_CFG = 0x00fe0105ul;
|
||||
|
||||
#ifdef CONFIG_CPU_SUPPORTS_ADDRWINCFG
|
||||
/*
|
||||
* set cpu addr window2 to map CPU address space to PCI address space
|
||||
*/
|
||||
LOONGSON_ADDRWIN_CPUTOPCI(ADDRWIN_WIN2, LOONGSON_CPU_MEM_SRC,
|
||||
LOONGSON_PCI_MEM_DST, MMAP_CPUTOPCI_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int __init pcibios_init(void)
|
||||
{
|
||||
setup_pcimap();
|
||||
|
||||
loongson_pci_controller.io_map_base = mips_io_port_base;
|
||||
#ifdef CONFIG_LEFI_FIRMWARE_INTERFACE
|
||||
loongson_pci_mem_resource.start = loongson_sysconf.pci_mem_start_addr;
|
||||
loongson_pci_mem_resource.end = loongson_sysconf.pci_mem_end_addr;
|
||||
#endif
|
||||
register_pci_controller(&loongson_pci_controller);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(pcibios_init);
|
||||
31
arch/mips/loongson/common/platform.c
Normal file
31
arch/mips/loongson/common/platform.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Lemote Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static struct platform_device loongson2_cpufreq_device = {
|
||||
.name = "loongson2_cpufreq",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static int __init loongson2_cpufreq_init(void)
|
||||
{
|
||||
struct cpuinfo_mips *c = ¤t_cpu_data;
|
||||
|
||||
/* Only 2F revision and it's successors support CPUFreq */
|
||||
if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON2F)
|
||||
return platform_device_register(&loongson2_cpufreq_device);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
arch_initcall(loongson2_cpufreq_init);
|
||||
161
arch/mips/loongson/common/pm.c
Normal file
161
arch/mips/loongson/common/pm.c
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* loongson-specific suspend support
|
||||
*
|
||||
* Copyright (C) 2009 Lemote Inc.
|
||||
* Author: Wu Zhangjin <wuzhangjin@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include <asm/i8259.h>
|
||||
#include <asm/mipsregs.h>
|
||||
|
||||
#include <loongson.h>
|
||||
|
||||
static unsigned int __maybe_unused cached_master_mask; /* i8259A */
|
||||
static unsigned int __maybe_unused cached_slave_mask;
|
||||
static unsigned int __maybe_unused cached_bonito_irq_mask; /* bonito */
|
||||
|
||||
void arch_suspend_disable_irqs(void)
|
||||
{
|
||||
/* disable all mips events */
|
||||
local_irq_disable();
|
||||
|
||||
#ifdef CONFIG_I8259
|
||||
/* disable all events of i8259A */
|
||||
cached_slave_mask = inb(PIC_SLAVE_IMR);
|
||||
cached_master_mask = inb(PIC_MASTER_IMR);
|
||||
|
||||
outb(0xff, PIC_SLAVE_IMR);
|
||||
inb(PIC_SLAVE_IMR);
|
||||
outb(0xff, PIC_MASTER_IMR);
|
||||
inb(PIC_MASTER_IMR);
|
||||
#endif
|
||||
/* disable all events of bonito */
|
||||
cached_bonito_irq_mask = LOONGSON_INTEN;
|
||||
LOONGSON_INTENCLR = 0xffff;
|
||||
(void)LOONGSON_INTENCLR;
|
||||
}
|
||||
|
||||
void arch_suspend_enable_irqs(void)
|
||||
{
|
||||
/* enable all mips events */
|
||||
local_irq_enable();
|
||||
#ifdef CONFIG_I8259
|
||||
/* only enable the cached events of i8259A */
|
||||
outb(cached_slave_mask, PIC_SLAVE_IMR);
|
||||
outb(cached_master_mask, PIC_MASTER_IMR);
|
||||
#endif
|
||||
/* enable all cached events of bonito */
|
||||
LOONGSON_INTENSET = cached_bonito_irq_mask;
|
||||
(void)LOONGSON_INTENSET;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the board-specific events for waking up loongson from wait mode
|
||||
*/
|
||||
void __weak setup_wakeup_events(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Check wakeup events
|
||||
*/
|
||||
int __weak wakeup_loongson(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the events are really what we want to wakeup the CPU, wake it up
|
||||
* otherwise put the CPU asleep again.
|
||||
*/
|
||||
static void wait_for_wakeup_events(void)
|
||||
{
|
||||
while (!wakeup_loongson())
|
||||
LOONGSON_CHIPCFG(0) &= ~0x7;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop all perf counters
|
||||
*
|
||||
* $24 is the control register of Loongson perf counter
|
||||
*/
|
||||
static inline void stop_perf_counters(void)
|
||||
{
|
||||
__write_64bit_c0_register($24, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
static void loongson_suspend_enter(void)
|
||||
{
|
||||
static unsigned int cached_cpu_freq;
|
||||
|
||||
/* setup wakeup events via enabling the IRQs */
|
||||
setup_wakeup_events();
|
||||
|
||||
stop_perf_counters();
|
||||
|
||||
cached_cpu_freq = LOONGSON_CHIPCFG(0);
|
||||
|
||||
/* Put CPU into wait mode */
|
||||
LOONGSON_CHIPCFG(0) &= ~0x7;
|
||||
|
||||
/* wait for the given events to wakeup cpu from wait mode */
|
||||
wait_for_wakeup_events();
|
||||
|
||||
LOONGSON_CHIPCFG(0) = cached_cpu_freq;
|
||||
mmiowb();
|
||||
}
|
||||
|
||||
void __weak mach_suspend(void)
|
||||
{
|
||||
}
|
||||
|
||||
void __weak mach_resume(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int loongson_pm_enter(suspend_state_t state)
|
||||
{
|
||||
mach_suspend();
|
||||
|
||||
/* processor specific suspend */
|
||||
loongson_suspend_enter();
|
||||
|
||||
mach_resume();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongson_pm_valid_state(suspend_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case PM_SUSPEND_ON:
|
||||
case PM_SUSPEND_STANDBY:
|
||||
case PM_SUSPEND_MEM:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct platform_suspend_ops loongson_pm_ops = {
|
||||
.valid = loongson_pm_valid_state,
|
||||
.enter = loongson_pm_enter,
|
||||
};
|
||||
|
||||
static int __init loongson_pm_init(void)
|
||||
{
|
||||
suspend_set_ops(&loongson_pm_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(loongson_pm_init);
|
||||
92
arch/mips/loongson/common/reset.c
Normal file
92
arch/mips/loongson/common/reset.c
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology
|
||||
* Author: Fuxin Zhang, zhangfx@lemote.com
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Zhangjin Wu, wuzhangjin@gmail.com
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include <asm/idle.h>
|
||||
#include <asm/reboot.h>
|
||||
|
||||
#include <loongson.h>
|
||||
#include <boot_param.h>
|
||||
|
||||
static inline void loongson_reboot(void)
|
||||
{
|
||||
#ifndef CONFIG_CPU_JUMP_WORKAROUNDS
|
||||
((void (*)(void))ioremap_nocache(LOONGSON_BOOT_BASE, 4)) ();
|
||||
#else
|
||||
void (*func)(void);
|
||||
|
||||
func = (void *)ioremap_nocache(LOONGSON_BOOT_BASE, 4);
|
||||
|
||||
__asm__ __volatile__(
|
||||
" .set noat \n"
|
||||
" jr %[func] \n"
|
||||
" .set at \n"
|
||||
: /* No outputs */
|
||||
: [func] "r" (func));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void loongson_restart(char *command)
|
||||
{
|
||||
#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
|
||||
/* do preparation for reboot */
|
||||
mach_prepare_reboot();
|
||||
|
||||
/* reboot via jumping to boot base address */
|
||||
loongson_reboot();
|
||||
#else
|
||||
void (*fw_restart)(void) = (void *)loongson_sysconf.restart_addr;
|
||||
|
||||
fw_restart();
|
||||
while (1) {
|
||||
if (cpu_wait)
|
||||
cpu_wait();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void loongson_poweroff(void)
|
||||
{
|
||||
#ifndef CONFIG_LEFI_FIRMWARE_INTERFACE
|
||||
mach_prepare_shutdown();
|
||||
unreachable();
|
||||
#else
|
||||
void (*fw_poweroff)(void) = (void *)loongson_sysconf.poweroff_addr;
|
||||
|
||||
fw_poweroff();
|
||||
while (1) {
|
||||
if (cpu_wait)
|
||||
cpu_wait();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void loongson_halt(void)
|
||||
{
|
||||
pr_notice("\n\n** You can safely turn off the power now **\n\n");
|
||||
while (1) {
|
||||
if (cpu_wait)
|
||||
cpu_wait();
|
||||
}
|
||||
}
|
||||
|
||||
static int __init mips_reboot_setup(void)
|
||||
{
|
||||
_machine_restart = loongson_restart;
|
||||
_machine_halt = loongson_halt;
|
||||
pm_power_off = loongson_poweroff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(mips_reboot_setup);
|
||||
43
arch/mips/loongson/common/rtc.c
Normal file
43
arch/mips/loongson/common/rtc.c
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Lemote Fuloong platform support
|
||||
*
|
||||
* Copyright(c) 2010 Arnaud Patard <apatard@mandriva.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
struct resource loongson_rtc_resources[] = {
|
||||
{
|
||||
.start = RTC_PORT(0),
|
||||
.end = RTC_PORT(1),
|
||||
.flags = IORESOURCE_IO,
|
||||
}, {
|
||||
.start = RTC_IRQ,
|
||||
.end = RTC_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device loongson_rtc_device = {
|
||||
.name = "rtc_cmos",
|
||||
.id = -1,
|
||||
.resource = loongson_rtc_resources,
|
||||
.num_resources = ARRAY_SIZE(loongson_rtc_resources),
|
||||
};
|
||||
|
||||
|
||||
static int __init loongson_rtc_platform_init(void)
|
||||
{
|
||||
platform_device_register(&loongson_rtc_device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_initcall(loongson_rtc_platform_init);
|
||||
80
arch/mips/loongson/common/serial.c
Normal file
80
arch/mips/loongson/common/serial.c
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
|
||||
*
|
||||
* Copyright (C) 2009 Lemote, Inc.
|
||||
* Author: Yan hua (yanhua@lemote.com)
|
||||
* Author: Wu Zhangjin (wuzhangjin@gmail.com)
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
#include <loongson.h>
|
||||
#include <machine.h>
|
||||
|
||||
#define PORT(int, clk) \
|
||||
{ \
|
||||
.irq = int, \
|
||||
.uartclk = clk, \
|
||||
.iotype = UPIO_PORT, \
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
|
||||
.regshift = 0, \
|
||||
}
|
||||
|
||||
#define PORT_M(int, clk) \
|
||||
{ \
|
||||
.irq = MIPS_CPU_IRQ_BASE + (int), \
|
||||
.uartclk = clk, \
|
||||
.iotype = UPIO_MEM, \
|
||||
.membase = (void __iomem *)NULL, \
|
||||
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \
|
||||
.regshift = 0, \
|
||||
}
|
||||
|
||||
static struct plat_serial8250_port uart8250_data[][2] = {
|
||||
[MACH_LOONGSON_UNKNOWN] {},
|
||||
[MACH_LEMOTE_FL2E] {PORT(4, 1843200), {} },
|
||||
[MACH_LEMOTE_FL2F] {PORT(3, 1843200), {} },
|
||||
[MACH_LEMOTE_ML2F7] {PORT_M(3, 3686400), {} },
|
||||
[MACH_LEMOTE_YL2F89] {PORT_M(3, 3686400), {} },
|
||||
[MACH_DEXXON_GDIUM2F10] {PORT_M(3, 3686400), {} },
|
||||
[MACH_LEMOTE_NAS] {PORT_M(3, 3686400), {} },
|
||||
[MACH_LEMOTE_LL2F] {PORT(3, 1843200), {} },
|
||||
[MACH_LEMOTE_A1004] {PORT_M(2, 33177600), {} },
|
||||
[MACH_LEMOTE_A1101] {PORT_M(2, 25000000), {} },
|
||||
[MACH_LEMOTE_A1201] {PORT_M(2, 25000000), {} },
|
||||
[MACH_LEMOTE_A1205] {PORT_M(2, 25000000), {} },
|
||||
[MACH_LOONGSON_END] {},
|
||||
};
|
||||
|
||||
static struct platform_device uart8250_device = {
|
||||
.name = "serial8250",
|
||||
.id = PLAT8250_DEV_PLATFORM,
|
||||
};
|
||||
|
||||
static int __init serial_init(void)
|
||||
{
|
||||
unsigned char iotype;
|
||||
|
||||
iotype = uart8250_data[mips_machtype][0].iotype;
|
||||
|
||||
if (UPIO_MEM == iotype)
|
||||
uart8250_data[mips_machtype][0].membase =
|
||||
(void __iomem *)_loongson_uart_base;
|
||||
else if (UPIO_PORT == iotype)
|
||||
uart8250_data[mips_machtype][0].iobase =
|
||||
loongson_uart_base - LOONGSON_PCIIO_BASE;
|
||||
|
||||
uart8250_device.dev.platform_data = uart8250_data[mips_machtype];
|
||||
|
||||
return platform_device_register(&uart8250_device);
|
||||
}
|
||||
|
||||
device_initcall(serial_init);
|
||||
53
arch/mips/loongson/common/setup.c
Normal file
53
arch/mips/loongson/common/setup.c
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology
|
||||
* Author: Fuxin Zhang, zhangfx@lemote.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/wbflush.h>
|
||||
|
||||
#include <loongson.h>
|
||||
|
||||
#ifdef CONFIG_VT
|
||||
#include <linux/console.h>
|
||||
#include <linux/screen_info.h>
|
||||
#endif
|
||||
|
||||
static void wbflush_loongson(void)
|
||||
{
|
||||
asm(".set\tpush\n\t"
|
||||
".set\tnoreorder\n\t"
|
||||
".set mips3\n\t"
|
||||
"sync\n\t"
|
||||
"nop\n\t"
|
||||
".set\tpop\n\t"
|
||||
".set mips0\n\t");
|
||||
}
|
||||
|
||||
void (*__wbflush)(void) = wbflush_loongson;
|
||||
EXPORT_SYMBOL(__wbflush);
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
#ifdef CONFIG_VT
|
||||
#if defined(CONFIG_VGA_CONSOLE)
|
||||
conswitchp = &vga_con;
|
||||
|
||||
screen_info = (struct screen_info) {
|
||||
.orig_x = 0,
|
||||
.orig_y = 25,
|
||||
.orig_video_cols = 80,
|
||||
.orig_video_lines = 25,
|
||||
.orig_video_isVGA = VIDEO_TYPE_VGAC,
|
||||
.orig_video_points = 16,
|
||||
};
|
||||
#elif defined(CONFIG_DUMMY_CONSOLE)
|
||||
conswitchp = &dummy_con;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
31
arch/mips/loongson/common/time.c
Normal file
31
arch/mips/loongson/common/time.c
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Lemote, Inc. & Institute of Computing Technology
|
||||
* Author: Fuxin Zhang, zhangfx@lemote.com
|
||||
*
|
||||
* Copyright (C) 2009 Lemote Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
#include <asm/mc146818-time.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
#include <loongson.h>
|
||||
#include <cs5536/cs5536_mfgpt.h>
|
||||
|
||||
void __init plat_time_init(void)
|
||||
{
|
||||
/* setup mips r4k timer */
|
||||
mips_hpt_frequency = cpu_clock_freq / 2;
|
||||
|
||||
setup_mfgpt0_timer();
|
||||
}
|
||||
|
||||
void read_persistent_clock(struct timespec *ts)
|
||||
{
|
||||
ts->tv_sec = mc146818_get_cmos_time();
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
52
arch/mips/loongson/common/uart_base.c
Normal file
52
arch/mips/loongson/common/uart_base.c
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Lemote Inc.
|
||||
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <asm/bootinfo.h>
|
||||
|
||||
#include <loongson.h>
|
||||
|
||||
/* ioremapped */
|
||||
unsigned long _loongson_uart_base;
|
||||
EXPORT_SYMBOL(_loongson_uart_base);
|
||||
/* raw */
|
||||
unsigned long loongson_uart_base;
|
||||
EXPORT_SYMBOL(loongson_uart_base);
|
||||
|
||||
void prom_init_loongson_uart_base(void)
|
||||
{
|
||||
switch (mips_machtype) {
|
||||
case MACH_LEMOTE_FL2E:
|
||||
loongson_uart_base = LOONGSON_PCIIO_BASE + 0x3f8;
|
||||
break;
|
||||
case MACH_LEMOTE_FL2F:
|
||||
case MACH_LEMOTE_LL2F:
|
||||
loongson_uart_base = LOONGSON_PCIIO_BASE + 0x2f8;
|
||||
break;
|
||||
case MACH_LEMOTE_ML2F7:
|
||||
case MACH_LEMOTE_YL2F89:
|
||||
case MACH_DEXXON_GDIUM2F10:
|
||||
case MACH_LEMOTE_NAS:
|
||||
default:
|
||||
/* The CPU provided serial port (LPC) */
|
||||
loongson_uart_base = LOONGSON_LIO1_BASE + 0x3f8;
|
||||
break;
|
||||
case MACH_LEMOTE_A1004:
|
||||
case MACH_LEMOTE_A1101:
|
||||
case MACH_LEMOTE_A1201:
|
||||
case MACH_LEMOTE_A1205:
|
||||
/* The CPU provided serial port (CPU) */
|
||||
loongson_uart_base = LOONGSON_REG_BASE + 0x1e0;
|
||||
break;
|
||||
}
|
||||
|
||||
_loongson_uart_base =
|
||||
(unsigned long)ioremap_nocache(loongson_uart_base, 8);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue