You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'powerpc-4.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc updates from Michael Ellerman:
"Core:
- Ground work for the new Power9 MMU from Aneesh Kumar K.V
- Optimise FP/VMX/VSX context switching from Anton Blanchard
Misc:
- Various cleanups from Krzysztof Kozlowski, John Ogness, Rashmica
Gupta, Russell Currey, Gavin Shan, Daniel Axtens, Michael Neuling,
Andrew Donnellan
- Allow wrapper to work on non-english system from Laurent Vivier
- Add rN aliases to the pt_regs_offset table from Rashmica Gupta
- Fix module autoload for rackmeter & axonram drivers from Luis de
Bethencourt
- Include KVM guest test in all interrupt vectors from Paul Mackerras
- Fix DSCR inheritance over fork() from Anton Blanchard
- Make value-returning atomics & {cmp}xchg* & their atomic_ versions
fully ordered from Boqun Feng
- Print MSR TM bits in oops messages from Michael Neuling
- Add TM signal return & invalid stack selftests from Michael Neuling
- Limit EPOW reset event warnings from Vipin K Parashar
- Remove the Cell QPACE code from Rashmica Gupta
- Append linux_banner to exception information in xmon from Rashmica
Gupta
- Add selftest to check if VSRs are corrupted from Rashmica Gupta
- Remove broken GregorianDay() from Daniel Axtens
- Import Anton's context_switch2 benchmark into selftests from
Michael Ellerman
- Add selftest script to test HMI functionality from Daniel Axtens
- Remove obsolete OPAL v2 support from Stewart Smith
- Make enter_rtas() private from Michael Ellerman
- PPR exception cleanups from Michael Ellerman
- Add page soft dirty tracking from Laurent Dufour
- Add support for Nvlink NPUs from Alistair Popple
- Add support for kexec on 476fpe from Alistair Popple
- Enable kernel CPU dlpar from sysfs from Nathan Fontenot
- Copy only required pieces of the mm_context_t to the paca from
Michael Neuling
- Add a kmsg_dumper that flushes OPAL console output on panic from
Russell Currey
- Implement save_stack_trace_regs() to enable kprobe stack tracing
from Steven Rostedt
- Add HWCAP bits for Power9 from Michael Ellerman
- Fix _PAGE_PTE breaking swapoff from Aneesh Kumar K.V
- Fix _PAGE_SWP_SOFT_DIRTY breaking swapoff from Hugh Dickins
- scripts/recordmcount.pl: support data in text section on powerpc
from Ulrich Weigand
- Handle R_PPC64_ENTRY relocations in modules from Ulrich Weigand
cxl:
- cxl: Fix possible idr warning when contexts are released from
Vaibhav Jain
- cxl: use correct operator when writing pcie config space values
from Andrew Donnellan
- cxl: Fix DSI misses when the context owning task exits from Vaibhav
Jain
- cxl: fix build for GCC 4.6.x from Brian Norris
- cxl: use -Werror only with CONFIG_PPC_WERROR from Brian Norris
- cxl: Enable PCI device ID for future IBM CXL adapter from Uma
Krishnan
Freescale:
- Freescale updates from Scott: Highlights include moving QE code out
of arch/powerpc (to be shared with arm), device tree updates, and
minor fixes"
* tag 'powerpc-4.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (149 commits)
powerpc/module: Handle R_PPC64_ENTRY relocations
scripts/recordmcount.pl: support data in text section on powerpc
powerpc/powernv: Fix OPAL_CONSOLE_FLUSH prototype and usages
powerpc/mm: fix _PAGE_SWP_SOFT_DIRTY breaking swapoff
powerpc/mm: Fix _PAGE_PTE breaking swapoff
cxl: Enable PCI device ID for future IBM CXL adapter
cxl: use -Werror only with CONFIG_PPC_WERROR
cxl: fix build for GCC 4.6.x
powerpc: Add HWCAP bits for Power9
powerpc/powernv: Reserve PE#0 on NPU
powerpc/powernv: Change NPU PE# assignment
powerpc/powernv: Fix update of NVLink DMA mask
powerpc/powernv: Remove misleading comment in pci.c
powerpc: Implement save_stack_trace_regs() to enable kprobe stack tracing
powerpc: Fix build break due to paca mm_context_t changes
cxl: Fix DSI misses when the context owning task exits
MAINTAINERS: Update Scott Wood's e-mail address
powerpc/powernv: Fix minor off-by-one error in opal_mce_check_early_recovery()
powerpc: Fix style of self-test config prompts
powerpc/powernv: Only delay opal_rtc_read() retry when necessary
...
This commit is contained in:
@@ -26,7 +26,6 @@ obj-$(CONFIG_FSL_85XX_CACHE_SRAM) += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
|
||||
obj-$(CONFIG_SIMPLE_GPIO) += simple_gpio.o
|
||||
obj-$(CONFIG_FSL_RIO) += fsl_rio.o fsl_rmu.o
|
||||
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
|
||||
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
|
||||
mv64x60-$(CONFIG_PCI) += mv64x60_pci.o
|
||||
obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \
|
||||
mv64x60_udbg.o
|
||||
|
||||
@@ -313,6 +313,7 @@ static const struct of_device_id axon_ram_device_id[] = {
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axon_ram_device_id);
|
||||
|
||||
static struct platform_driver axon_ram_driver = {
|
||||
.probe = axon_ram_probe,
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
|
||||
#include <asm/udbg.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/rheap.h>
|
||||
#include <asm/cpm.h>
|
||||
#include <soc/fsl/qe/qe.h>
|
||||
|
||||
#include <mm/mmu_decl.h>
|
||||
|
||||
@@ -65,162 +65,6 @@ void __init udbg_init_cpm(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static spinlock_t cpm_muram_lock;
|
||||
static rh_block_t cpm_boot_muram_rh_block[16];
|
||||
static rh_info_t cpm_muram_info;
|
||||
static u8 __iomem *muram_vbase;
|
||||
static phys_addr_t muram_pbase;
|
||||
|
||||
/* Max address size we deal with */
|
||||
#define OF_MAX_ADDR_CELLS 4
|
||||
|
||||
int cpm_muram_init(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct resource r;
|
||||
u32 zero[OF_MAX_ADDR_CELLS] = {};
|
||||
resource_size_t max = 0;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (muram_pbase)
|
||||
return 0;
|
||||
|
||||
spin_lock_init(&cpm_muram_lock);
|
||||
/* initialize the info header */
|
||||
rh_init(&cpm_muram_info, 1,
|
||||
sizeof(cpm_boot_muram_rh_block) /
|
||||
sizeof(cpm_boot_muram_rh_block[0]),
|
||||
cpm_boot_muram_rh_block);
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,cpm-muram-data");
|
||||
if (!np) {
|
||||
/* try legacy bindings */
|
||||
np = of_find_node_by_name(NULL, "data-only");
|
||||
if (!np) {
|
||||
printk(KERN_ERR "Cannot find CPM muram data node");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
muram_pbase = of_translate_address(np, zero);
|
||||
if (muram_pbase == (phys_addr_t)OF_BAD_ADDR) {
|
||||
printk(KERN_ERR "Cannot translate zero through CPM muram node");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (of_address_to_resource(np, i++, &r) == 0) {
|
||||
if (r.end > max)
|
||||
max = r.end;
|
||||
|
||||
rh_attach_region(&cpm_muram_info, r.start - muram_pbase,
|
||||
resource_size(&r));
|
||||
}
|
||||
|
||||
muram_vbase = ioremap(muram_pbase, max - muram_pbase + 1);
|
||||
if (!muram_vbase) {
|
||||
printk(KERN_ERR "Cannot map CPM muram");
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
|
||||
out:
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cpm_muram_alloc - allocate the requested size worth of multi-user ram
|
||||
* @size: number of bytes to allocate
|
||||
* @align: requested alignment, in bytes
|
||||
*
|
||||
* This function returns an offset into the muram area.
|
||||
* Use cpm_dpram_addr() to get the virtual address of the area.
|
||||
* Use cpm_muram_free() to free the allocation.
|
||||
*/
|
||||
unsigned long cpm_muram_alloc(unsigned long size, unsigned long align)
|
||||
{
|
||||
unsigned long start;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&cpm_muram_lock, flags);
|
||||
cpm_muram_info.alignment = align;
|
||||
start = rh_alloc(&cpm_muram_info, size, "commproc");
|
||||
if (!IS_ERR_VALUE(start))
|
||||
memset_io(cpm_muram_addr(start), 0, size);
|
||||
spin_unlock_irqrestore(&cpm_muram_lock, flags);
|
||||
|
||||
return start;
|
||||
}
|
||||
EXPORT_SYMBOL(cpm_muram_alloc);
|
||||
|
||||
/**
|
||||
* cpm_muram_free - free a chunk of multi-user ram
|
||||
* @offset: The beginning of the chunk as returned by cpm_muram_alloc().
|
||||
*/
|
||||
int cpm_muram_free(unsigned long offset)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&cpm_muram_lock, flags);
|
||||
ret = rh_free(&cpm_muram_info, offset);
|
||||
spin_unlock_irqrestore(&cpm_muram_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cpm_muram_free);
|
||||
|
||||
/**
|
||||
* cpm_muram_alloc_fixed - reserve a specific region of multi-user ram
|
||||
* @offset: the offset into the muram area to reserve
|
||||
* @size: the number of bytes to reserve
|
||||
*
|
||||
* This function returns "start" on success, -ENOMEM on failure.
|
||||
* Use cpm_dpram_addr() to get the virtual address of the area.
|
||||
* Use cpm_muram_free() to free the allocation.
|
||||
*/
|
||||
unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size)
|
||||
{
|
||||
unsigned long start;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&cpm_muram_lock, flags);
|
||||
cpm_muram_info.alignment = 1;
|
||||
start = rh_alloc_fixed(&cpm_muram_info, offset, size, "commproc");
|
||||
spin_unlock_irqrestore(&cpm_muram_lock, flags);
|
||||
|
||||
return start;
|
||||
}
|
||||
EXPORT_SYMBOL(cpm_muram_alloc_fixed);
|
||||
|
||||
/**
|
||||
* cpm_muram_addr - turn a muram offset into a virtual address
|
||||
* @offset: muram offset to convert
|
||||
*/
|
||||
void __iomem *cpm_muram_addr(unsigned long offset)
|
||||
{
|
||||
return muram_vbase + offset;
|
||||
}
|
||||
EXPORT_SYMBOL(cpm_muram_addr);
|
||||
|
||||
unsigned long cpm_muram_offset(void __iomem *addr)
|
||||
{
|
||||
return addr - (void __iomem *)muram_vbase;
|
||||
}
|
||||
EXPORT_SYMBOL(cpm_muram_offset);
|
||||
|
||||
/**
|
||||
* cpm_muram_dma - turn a muram virtual address into a DMA address
|
||||
* @offset: virtual address from cpm_muram_addr() to convert
|
||||
*/
|
||||
dma_addr_t cpm_muram_dma(void __iomem *addr)
|
||||
{
|
||||
return muram_pbase + ((u8 __iomem *)addr - muram_vbase);
|
||||
}
|
||||
EXPORT_SYMBOL(cpm_muram_dma);
|
||||
|
||||
#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
|
||||
|
||||
struct cpm2_ioports {
|
||||
|
||||
@@ -243,8 +243,6 @@ static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
|
||||
if (status & LTESR_CS)
|
||||
dev_err(ctrl->dev, "Chip select error: "
|
||||
"LTESR 0x%08X\n", status);
|
||||
if (status & LTESR_UPM)
|
||||
;
|
||||
if (status & LTESR_FCT) {
|
||||
dev_err(ctrl->dev, "FCM command time-out: "
|
||||
"LTESR 0x%08X\n", status);
|
||||
|
||||
@@ -218,6 +218,19 @@ static void setup_pci_atmu(struct pci_controller *hose)
|
||||
*/
|
||||
setup_inbound = !is_kdump();
|
||||
|
||||
if (of_device_is_compatible(hose->dn, "fsl,bsc9132-pcie")) {
|
||||
/*
|
||||
* BSC9132 Rev1.0 has an issue where all the PEX inbound
|
||||
* windows have implemented the default target value as 0xf
|
||||
* for CCSR space.In all Freescale legacy devices the target
|
||||
* of 0xf is reserved for local memory space. 9132 Rev1.0
|
||||
* now has local mempry space mapped to target 0x0 instead of
|
||||
* 0xf. Hence adding a workaround to remove the target 0xf
|
||||
* defined for memory space from Inbound window attributes.
|
||||
*/
|
||||
piwar &= ~PIWAR_TGI_LOCAL;
|
||||
}
|
||||
|
||||
if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
|
||||
if (in_be32(&pci->block_rev1) >= PCIE_IP_REV_2_2) {
|
||||
win_idx = 2;
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# QE Communication options
|
||||
#
|
||||
|
||||
config UCC_SLOW
|
||||
bool
|
||||
default y if SERIAL_QE
|
||||
help
|
||||
This option provides qe_lib support to UCC slow
|
||||
protocols: UART, BISYNC, QMC
|
||||
|
||||
config UCC_FAST
|
||||
bool
|
||||
default y if UCC_GETH
|
||||
help
|
||||
This option provides qe_lib support to UCC fast
|
||||
protocols: HDLC, Ethernet, ATM, transparent
|
||||
|
||||
config UCC
|
||||
bool
|
||||
default y if UCC_FAST || UCC_SLOW
|
||||
|
||||
config QE_USB
|
||||
bool
|
||||
default y if USB_FSL_QE
|
||||
help
|
||||
QE USB Controller support
|
||||
@@ -1,10 +0,0 @@
|
||||
#
|
||||
# Makefile for the linux ppc-specific parts of QE
|
||||
#
|
||||
obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_ic.o qe_io.o
|
||||
|
||||
obj-$(CONFIG_UCC) += ucc.o
|
||||
obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
|
||||
obj-$(CONFIG_UCC_FAST) += ucc_fast.o
|
||||
obj-$(CONFIG_QE_USB) += usb.o
|
||||
obj-$(CONFIG_QE_GPIO) += gpio.o
|
||||
@@ -1,317 +0,0 @@
|
||||
/*
|
||||
* QUICC Engine GPIOs
|
||||
*
|
||||
* Copyright (c) MontaVista Software, Inc. 2008.
|
||||
*
|
||||
* Author: Anton Vorontsov <avorontsov@ru.mvista.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/spinlock.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/qe.h>
|
||||
|
||||
struct qe_gpio_chip {
|
||||
struct of_mm_gpio_chip mm_gc;
|
||||
spinlock_t lock;
|
||||
|
||||
unsigned long pin_flags[QE_PIO_PINS];
|
||||
#define QE_PIN_REQUESTED 0
|
||||
|
||||
/* shadowed data register to clear/set bits safely */
|
||||
u32 cpdata;
|
||||
|
||||
/* saved_regs used to restore dedicated functions */
|
||||
struct qe_pio_regs saved_regs;
|
||||
};
|
||||
|
||||
static inline struct qe_gpio_chip *
|
||||
to_qe_gpio_chip(struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
return container_of(mm_gc, struct qe_gpio_chip, mm_gc);
|
||||
}
|
||||
|
||||
static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
|
||||
{
|
||||
struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
|
||||
struct qe_pio_regs __iomem *regs = mm_gc->regs;
|
||||
|
||||
qe_gc->cpdata = in_be32(®s->cpdata);
|
||||
qe_gc->saved_regs.cpdata = qe_gc->cpdata;
|
||||
qe_gc->saved_regs.cpdir1 = in_be32(®s->cpdir1);
|
||||
qe_gc->saved_regs.cpdir2 = in_be32(®s->cpdir2);
|
||||
qe_gc->saved_regs.cppar1 = in_be32(®s->cppar1);
|
||||
qe_gc->saved_regs.cppar2 = in_be32(®s->cppar2);
|
||||
qe_gc->saved_regs.cpodr = in_be32(®s->cpodr);
|
||||
}
|
||||
|
||||
static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct qe_pio_regs __iomem *regs = mm_gc->regs;
|
||||
u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
|
||||
|
||||
return in_be32(®s->cpdata) & pin_mask;
|
||||
}
|
||||
|
||||
static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
|
||||
struct qe_pio_regs __iomem *regs = mm_gc->regs;
|
||||
unsigned long flags;
|
||||
u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
|
||||
|
||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
||||
|
||||
if (val)
|
||||
qe_gc->cpdata |= pin_mask;
|
||||
else
|
||||
qe_gc->cpdata &= ~pin_mask;
|
||||
|
||||
out_be32(®s->cpdata, qe_gc->cpdata);
|
||||
|
||||
spin_unlock_irqrestore(&qe_gc->lock, flags);
|
||||
}
|
||||
|
||||
static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
||||
|
||||
__par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_IN, 0, 0, 0);
|
||||
|
||||
spin_unlock_irqrestore(&qe_gc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
|
||||
struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
|
||||
unsigned long flags;
|
||||
|
||||
qe_gpio_set(gc, gpio, val);
|
||||
|
||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
||||
|
||||
__par_io_config_pin(mm_gc->regs, gpio, QE_PIO_DIR_OUT, 0, 0, 0);
|
||||
|
||||
spin_unlock_irqrestore(&qe_gc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct qe_pin {
|
||||
/*
|
||||
* The qe_gpio_chip name is unfortunate, we should change that to
|
||||
* something like qe_pio_controller. Someday.
|
||||
*/
|
||||
struct qe_gpio_chip *controller;
|
||||
int num;
|
||||
};
|
||||
|
||||
/**
|
||||
* qe_pin_request - Request a QE pin
|
||||
* @np: device node to get a pin from
|
||||
* @index: index of a pin in the device tree
|
||||
* Context: non-atomic
|
||||
*
|
||||
* This function return qe_pin so that you could use it with the rest of
|
||||
* the QE Pin Multiplexing API.
|
||||
*/
|
||||
struct qe_pin *qe_pin_request(struct device_node *np, int index)
|
||||
{
|
||||
struct qe_pin *qe_pin;
|
||||
struct gpio_chip *gc;
|
||||
struct of_mm_gpio_chip *mm_gc;
|
||||
struct qe_gpio_chip *qe_gc;
|
||||
int err;
|
||||
unsigned long flags;
|
||||
|
||||
qe_pin = kzalloc(sizeof(*qe_pin), GFP_KERNEL);
|
||||
if (!qe_pin) {
|
||||
pr_debug("%s: can't allocate memory\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
err = of_get_gpio(np, index);
|
||||
if (err < 0)
|
||||
goto err0;
|
||||
gc = gpio_to_chip(err);
|
||||
if (WARN_ON(!gc))
|
||||
goto err0;
|
||||
|
||||
if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) {
|
||||
pr_debug("%s: tried to get a non-qe pin\n", __func__);
|
||||
err = -EINVAL;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
mm_gc = to_of_mm_gpio_chip(gc);
|
||||
qe_gc = to_qe_gpio_chip(mm_gc);
|
||||
|
||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
||||
|
||||
err -= gc->base;
|
||||
if (test_and_set_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[err]) == 0) {
|
||||
qe_pin->controller = qe_gc;
|
||||
qe_pin->num = err;
|
||||
err = 0;
|
||||
} else {
|
||||
err = -EBUSY;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&qe_gc->lock, flags);
|
||||
|
||||
if (!err)
|
||||
return qe_pin;
|
||||
err0:
|
||||
kfree(qe_pin);
|
||||
pr_debug("%s failed with status %d\n", __func__, err);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL(qe_pin_request);
|
||||
|
||||
/**
|
||||
* qe_pin_free - Free a pin
|
||||
* @qe_pin: pointer to the qe_pin structure
|
||||
* Context: any
|
||||
*
|
||||
* This function frees the qe_pin structure and makes a pin available
|
||||
* for further qe_pin_request() calls.
|
||||
*/
|
||||
void qe_pin_free(struct qe_pin *qe_pin)
|
||||
{
|
||||
struct qe_gpio_chip *qe_gc = qe_pin->controller;
|
||||
unsigned long flags;
|
||||
const int pin = qe_pin->num;
|
||||
|
||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
||||
test_and_clear_bit(QE_PIN_REQUESTED, &qe_gc->pin_flags[pin]);
|
||||
spin_unlock_irqrestore(&qe_gc->lock, flags);
|
||||
|
||||
kfree(qe_pin);
|
||||
}
|
||||
EXPORT_SYMBOL(qe_pin_free);
|
||||
|
||||
/**
|
||||
* qe_pin_set_dedicated - Revert a pin to a dedicated peripheral function mode
|
||||
* @qe_pin: pointer to the qe_pin structure
|
||||
* Context: any
|
||||
*
|
||||
* This function resets a pin to a dedicated peripheral function that
|
||||
* has been set up by the firmware.
|
||||
*/
|
||||
void qe_pin_set_dedicated(struct qe_pin *qe_pin)
|
||||
{
|
||||
struct qe_gpio_chip *qe_gc = qe_pin->controller;
|
||||
struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs;
|
||||
struct qe_pio_regs *sregs = &qe_gc->saved_regs;
|
||||
int pin = qe_pin->num;
|
||||
u32 mask1 = 1 << (QE_PIO_PINS - (pin + 1));
|
||||
u32 mask2 = 0x3 << (QE_PIO_PINS - (pin % (QE_PIO_PINS / 2) + 1) * 2);
|
||||
bool second_reg = pin > (QE_PIO_PINS / 2) - 1;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
||||
|
||||
if (second_reg) {
|
||||
clrsetbits_be32(®s->cpdir2, mask2, sregs->cpdir2 & mask2);
|
||||
clrsetbits_be32(®s->cppar2, mask2, sregs->cppar2 & mask2);
|
||||
} else {
|
||||
clrsetbits_be32(®s->cpdir1, mask2, sregs->cpdir1 & mask2);
|
||||
clrsetbits_be32(®s->cppar1, mask2, sregs->cppar1 & mask2);
|
||||
}
|
||||
|
||||
if (sregs->cpdata & mask1)
|
||||
qe_gc->cpdata |= mask1;
|
||||
else
|
||||
qe_gc->cpdata &= ~mask1;
|
||||
|
||||
out_be32(®s->cpdata, qe_gc->cpdata);
|
||||
clrsetbits_be32(®s->cpodr, mask1, sregs->cpodr & mask1);
|
||||
|
||||
spin_unlock_irqrestore(&qe_gc->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(qe_pin_set_dedicated);
|
||||
|
||||
/**
|
||||
* qe_pin_set_gpio - Set a pin to the GPIO mode
|
||||
* @qe_pin: pointer to the qe_pin structure
|
||||
* Context: any
|
||||
*
|
||||
* This function sets a pin to the GPIO mode.
|
||||
*/
|
||||
void qe_pin_set_gpio(struct qe_pin *qe_pin)
|
||||
{
|
||||
struct qe_gpio_chip *qe_gc = qe_pin->controller;
|
||||
struct qe_pio_regs __iomem *regs = qe_gc->mm_gc.regs;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&qe_gc->lock, flags);
|
||||
|
||||
/* Let's make it input by default, GPIO API is able to change that. */
|
||||
__par_io_config_pin(regs, qe_pin->num, QE_PIO_DIR_IN, 0, 0, 0);
|
||||
|
||||
spin_unlock_irqrestore(&qe_gc->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(qe_pin_set_gpio);
|
||||
|
||||
static int __init qe_add_gpiochips(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
for_each_compatible_node(np, NULL, "fsl,mpc8323-qe-pario-bank") {
|
||||
int ret;
|
||||
struct qe_gpio_chip *qe_gc;
|
||||
struct of_mm_gpio_chip *mm_gc;
|
||||
struct gpio_chip *gc;
|
||||
|
||||
qe_gc = kzalloc(sizeof(*qe_gc), GFP_KERNEL);
|
||||
if (!qe_gc) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
spin_lock_init(&qe_gc->lock);
|
||||
|
||||
mm_gc = &qe_gc->mm_gc;
|
||||
gc = &mm_gc->gc;
|
||||
|
||||
mm_gc->save_regs = qe_gpio_save_regs;
|
||||
gc->ngpio = QE_PIO_PINS;
|
||||
gc->direction_input = qe_gpio_dir_in;
|
||||
gc->direction_output = qe_gpio_dir_out;
|
||||
gc->get = qe_gpio_get;
|
||||
gc->set = qe_gpio_set;
|
||||
|
||||
ret = of_mm_gpiochip_add(np, mm_gc);
|
||||
if (ret)
|
||||
goto err;
|
||||
continue;
|
||||
err:
|
||||
pr_err("%s: registration failed with status %d\n",
|
||||
np->full_name, ret);
|
||||
kfree(qe_gc);
|
||||
/* try others anyway */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(qe_add_gpiochips);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,103 +0,0 @@
|
||||
/*
|
||||
* arch/powerpc/sysdev/qe_lib/qe_ic.h
|
||||
*
|
||||
* QUICC ENGINE Interrupt Controller Header
|
||||
*
|
||||
* Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Li Yang <leoli@freescale.com>
|
||||
* Based on code from Shlomi Gridish <gridish@freescale.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.
|
||||
*/
|
||||
#ifndef _POWERPC_SYSDEV_QE_IC_H
|
||||
#define _POWERPC_SYSDEV_QE_IC_H
|
||||
|
||||
#include <asm/qe_ic.h>
|
||||
|
||||
#define NR_QE_IC_INTS 64
|
||||
|
||||
/* QE IC registers offset */
|
||||
#define QEIC_CICR 0x00
|
||||
#define QEIC_CIVEC 0x04
|
||||
#define QEIC_CRIPNR 0x08
|
||||
#define QEIC_CIPNR 0x0c
|
||||
#define QEIC_CIPXCC 0x10
|
||||
#define QEIC_CIPYCC 0x14
|
||||
#define QEIC_CIPWCC 0x18
|
||||
#define QEIC_CIPZCC 0x1c
|
||||
#define QEIC_CIMR 0x20
|
||||
#define QEIC_CRIMR 0x24
|
||||
#define QEIC_CICNR 0x28
|
||||
#define QEIC_CIPRTA 0x30
|
||||
#define QEIC_CIPRTB 0x34
|
||||
#define QEIC_CRICR 0x3c
|
||||
#define QEIC_CHIVEC 0x60
|
||||
|
||||
/* Interrupt priority registers */
|
||||
#define CIPCC_SHIFT_PRI0 29
|
||||
#define CIPCC_SHIFT_PRI1 26
|
||||
#define CIPCC_SHIFT_PRI2 23
|
||||
#define CIPCC_SHIFT_PRI3 20
|
||||
#define CIPCC_SHIFT_PRI4 13
|
||||
#define CIPCC_SHIFT_PRI5 10
|
||||
#define CIPCC_SHIFT_PRI6 7
|
||||
#define CIPCC_SHIFT_PRI7 4
|
||||
|
||||
/* CICR priority modes */
|
||||
#define CICR_GWCC 0x00040000
|
||||
#define CICR_GXCC 0x00020000
|
||||
#define CICR_GYCC 0x00010000
|
||||
#define CICR_GZCC 0x00080000
|
||||
#define CICR_GRTA 0x00200000
|
||||
#define CICR_GRTB 0x00400000
|
||||
#define CICR_HPIT_SHIFT 8
|
||||
#define CICR_HPIT_MASK 0x00000300
|
||||
#define CICR_HP_SHIFT 24
|
||||
#define CICR_HP_MASK 0x3f000000
|
||||
|
||||
/* CICNR */
|
||||
#define CICNR_WCC1T_SHIFT 20
|
||||
#define CICNR_ZCC1T_SHIFT 28
|
||||
#define CICNR_YCC1T_SHIFT 12
|
||||
#define CICNR_XCC1T_SHIFT 4
|
||||
|
||||
/* CRICR */
|
||||
#define CRICR_RTA1T_SHIFT 20
|
||||
#define CRICR_RTB1T_SHIFT 28
|
||||
|
||||
/* Signal indicator */
|
||||
#define SIGNAL_MASK 3
|
||||
#define SIGNAL_HIGH 2
|
||||
#define SIGNAL_LOW 0
|
||||
|
||||
struct qe_ic {
|
||||
/* Control registers offset */
|
||||
volatile u32 __iomem *regs;
|
||||
|
||||
/* The remapper for this QEIC */
|
||||
struct irq_domain *irqhost;
|
||||
|
||||
/* The "linux" controller struct */
|
||||
struct irq_chip hc_irq;
|
||||
|
||||
/* VIRQ numbers of QE high/low irqs */
|
||||
unsigned int virq_high;
|
||||
unsigned int virq_low;
|
||||
};
|
||||
|
||||
/*
|
||||
* QE interrupt controller internal structure
|
||||
*/
|
||||
struct qe_ic_info {
|
||||
u32 mask; /* location of this source at the QIMR register. */
|
||||
u32 mask_reg; /* Mask register offset */
|
||||
u8 pri_code; /* for grouped interrupts sources - the interrupt
|
||||
code as appears at the group priority register */
|
||||
u32 pri_reg; /* Group priority register offset */
|
||||
};
|
||||
|
||||
#endif /* _POWERPC_SYSDEV_QE_IC_H */
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* arch/powerpc/sysdev/qe_lib/qe_io.c
|
||||
*
|
||||
* QE Parallel I/O ports configuration routines
|
||||
*
|
||||
* Copyright 2006 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Author: Li Yang <LeoLi@freescale.com>
|
||||
* Based on code from Shlomi Gridish <gridish@freescale.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/stddef.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/qe.h>
|
||||
#include <asm/prom.h>
|
||||
#include <sysdev/fsl_soc.h>
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
static struct qe_pio_regs __iomem *par_io;
|
||||
static int num_par_io_ports = 0;
|
||||
|
||||
int par_io_init(struct device_node *np)
|
||||
{
|
||||
struct resource res;
|
||||
int ret;
|
||||
const u32 *num_ports;
|
||||
|
||||
/* Map Parallel I/O ports registers */
|
||||
ret = of_address_to_resource(np, 0, &res);
|
||||
if (ret)
|
||||
return ret;
|
||||
par_io = ioremap(res.start, resource_size(&res));
|
||||
|
||||
num_ports = of_get_property(np, "num-ports", NULL);
|
||||
if (num_ports)
|
||||
num_par_io_ports = *num_ports;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir,
|
||||
int open_drain, int assignment, int has_irq)
|
||||
{
|
||||
u32 pin_mask1bit;
|
||||
u32 pin_mask2bits;
|
||||
u32 new_mask2bits;
|
||||
u32 tmp_val;
|
||||
|
||||
/* calculate pin location for single and 2 bits information */
|
||||
pin_mask1bit = (u32) (1 << (QE_PIO_PINS - (pin + 1)));
|
||||
|
||||
/* Set open drain, if required */
|
||||
tmp_val = in_be32(&par_io->cpodr);
|
||||
if (open_drain)
|
||||
out_be32(&par_io->cpodr, pin_mask1bit | tmp_val);
|
||||
else
|
||||
out_be32(&par_io->cpodr, ~pin_mask1bit & tmp_val);
|
||||
|
||||
/* define direction */
|
||||
tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ?
|
||||
in_be32(&par_io->cpdir2) :
|
||||
in_be32(&par_io->cpdir1);
|
||||
|
||||
/* get all bits mask for 2 bit per port */
|
||||
pin_mask2bits = (u32) (0x3 << (QE_PIO_PINS -
|
||||
(pin % (QE_PIO_PINS / 2) + 1) * 2));
|
||||
|
||||
/* Get the final mask we need for the right definition */
|
||||
new_mask2bits = (u32) (dir << (QE_PIO_PINS -
|
||||
(pin % (QE_PIO_PINS / 2) + 1) * 2));
|
||||
|
||||
/* clear and set 2 bits mask */
|
||||
if (pin > (QE_PIO_PINS / 2) - 1) {
|
||||
out_be32(&par_io->cpdir2,
|
||||
~pin_mask2bits & tmp_val);
|
||||
tmp_val &= ~pin_mask2bits;
|
||||
out_be32(&par_io->cpdir2, new_mask2bits | tmp_val);
|
||||
} else {
|
||||
out_be32(&par_io->cpdir1,
|
||||
~pin_mask2bits & tmp_val);
|
||||
tmp_val &= ~pin_mask2bits;
|
||||
out_be32(&par_io->cpdir1, new_mask2bits | tmp_val);
|
||||
}
|
||||
/* define pin assignment */
|
||||
tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ?
|
||||
in_be32(&par_io->cppar2) :
|
||||
in_be32(&par_io->cppar1);
|
||||
|
||||
new_mask2bits = (u32) (assignment << (QE_PIO_PINS -
|
||||
(pin % (QE_PIO_PINS / 2) + 1) * 2));
|
||||
/* clear and set 2 bits mask */
|
||||
if (pin > (QE_PIO_PINS / 2) - 1) {
|
||||
out_be32(&par_io->cppar2,
|
||||
~pin_mask2bits & tmp_val);
|
||||
tmp_val &= ~pin_mask2bits;
|
||||
out_be32(&par_io->cppar2, new_mask2bits | tmp_val);
|
||||
} else {
|
||||
out_be32(&par_io->cppar1,
|
||||
~pin_mask2bits & tmp_val);
|
||||
tmp_val &= ~pin_mask2bits;
|
||||
out_be32(&par_io->cppar1, new_mask2bits | tmp_val);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(__par_io_config_pin);
|
||||
|
||||
int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
|
||||
int assignment, int has_irq)
|
||||
{
|
||||
if (!par_io || port >= num_par_io_ports)
|
||||
return -EINVAL;
|
||||
|
||||
__par_io_config_pin(&par_io[port], pin, dir, open_drain, assignment,
|
||||
has_irq);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(par_io_config_pin);
|
||||
|
||||
int par_io_data_set(u8 port, u8 pin, u8 val)
|
||||
{
|
||||
u32 pin_mask, tmp_val;
|
||||
|
||||
if (port >= num_par_io_ports)
|
||||
return -EINVAL;
|
||||
if (pin >= QE_PIO_PINS)
|
||||
return -EINVAL;
|
||||
/* calculate pin location */
|
||||
pin_mask = (u32) (1 << (QE_PIO_PINS - 1 - pin));
|
||||
|
||||
tmp_val = in_be32(&par_io[port].cpdata);
|
||||
|
||||
if (val == 0) /* clear */
|
||||
out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val);
|
||||
else /* set */
|
||||
out_be32(&par_io[port].cpdata, pin_mask | tmp_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(par_io_data_set);
|
||||
|
||||
int par_io_of_config(struct device_node *np)
|
||||
{
|
||||
struct device_node *pio;
|
||||
const phandle *ph;
|
||||
int pio_map_len;
|
||||
const unsigned int *pio_map;
|
||||
|
||||
if (par_io == NULL) {
|
||||
printk(KERN_ERR "par_io not initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ph = of_get_property(np, "pio-handle", NULL);
|
||||
if (ph == NULL) {
|
||||
printk(KERN_ERR "pio-handle not available\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pio = of_find_node_by_phandle(*ph);
|
||||
|
||||
pio_map = of_get_property(pio, "pio-map", &pio_map_len);
|
||||
if (pio_map == NULL) {
|
||||
printk(KERN_ERR "pio-map is not set!\n");
|
||||
return -1;
|
||||
}
|
||||
pio_map_len /= sizeof(unsigned int);
|
||||
if ((pio_map_len % 6) != 0) {
|
||||
printk(KERN_ERR "pio-map format wrong!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (pio_map_len > 0) {
|
||||
par_io_config_pin((u8) pio_map[0], (u8) pio_map[1],
|
||||
(int) pio_map[2], (int) pio_map[3],
|
||||
(int) pio_map[4], (int) pio_map[5]);
|
||||
pio_map += 6;
|
||||
pio_map_len -= 6;
|
||||
}
|
||||
of_node_put(pio);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(par_io_of_config);
|
||||
@@ -1,212 +0,0 @@
|
||||
/*
|
||||
* arch/powerpc/sysdev/qe_lib/ucc.c
|
||||
*
|
||||
* QE UCC API Set - UCC specific routines implementations.
|
||||
*
|
||||
* Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Authors: Shlomi Gridish <gridish@freescale.com>
|
||||
* Li Yang <leoli@freescale.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/errno.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_qe.h>
|
||||
#include <asm/qe.h>
|
||||
#include <asm/ucc.h>
|
||||
|
||||
int ucc_set_qe_mux_mii_mng(unsigned int ucc_num)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (ucc_num > UCC_MAX_NUM - 1)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&cmxgcr_lock, flags);
|
||||
clrsetbits_be32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG,
|
||||
ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
|
||||
spin_unlock_irqrestore(&cmxgcr_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_set_qe_mux_mii_mng);
|
||||
|
||||
/* Configure the UCC to either Slow or Fast.
|
||||
*
|
||||
* A given UCC can be figured to support either "slow" devices (e.g. UART)
|
||||
* or "fast" devices (e.g. Ethernet).
|
||||
*
|
||||
* 'ucc_num' is the UCC number, from 0 - 7.
|
||||
*
|
||||
* This function also sets the UCC_GUEMR_SET_RESERVED3 bit because that bit
|
||||
* must always be set to 1.
|
||||
*/
|
||||
int ucc_set_type(unsigned int ucc_num, enum ucc_speed_type speed)
|
||||
{
|
||||
u8 __iomem *guemr;
|
||||
|
||||
/* The GUEMR register is at the same location for both slow and fast
|
||||
devices, so we just use uccX.slow.guemr. */
|
||||
switch (ucc_num) {
|
||||
case 0: guemr = &qe_immr->ucc1.slow.guemr;
|
||||
break;
|
||||
case 1: guemr = &qe_immr->ucc2.slow.guemr;
|
||||
break;
|
||||
case 2: guemr = &qe_immr->ucc3.slow.guemr;
|
||||
break;
|
||||
case 3: guemr = &qe_immr->ucc4.slow.guemr;
|
||||
break;
|
||||
case 4: guemr = &qe_immr->ucc5.slow.guemr;
|
||||
break;
|
||||
case 5: guemr = &qe_immr->ucc6.slow.guemr;
|
||||
break;
|
||||
case 6: guemr = &qe_immr->ucc7.slow.guemr;
|
||||
break;
|
||||
case 7: guemr = &qe_immr->ucc8.slow.guemr;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clrsetbits_8(guemr, UCC_GUEMR_MODE_MASK,
|
||||
UCC_GUEMR_SET_RESERVED3 | speed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_cmxucr_reg(unsigned int ucc_num, __be32 __iomem **cmxucr,
|
||||
unsigned int *reg_num, unsigned int *shift)
|
||||
{
|
||||
unsigned int cmx = ((ucc_num & 1) << 1) + (ucc_num > 3);
|
||||
|
||||
*reg_num = cmx + 1;
|
||||
*cmxucr = &qe_immr->qmx.cmxucr[cmx];
|
||||
*shift = 16 - 8 * (ucc_num & 2);
|
||||
}
|
||||
|
||||
int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask)
|
||||
{
|
||||
__be32 __iomem *cmxucr;
|
||||
unsigned int reg_num;
|
||||
unsigned int shift;
|
||||
|
||||
/* check if the UCC number is in range. */
|
||||
if (ucc_num > UCC_MAX_NUM - 1)
|
||||
return -EINVAL;
|
||||
|
||||
get_cmxucr_reg(ucc_num, &cmxucr, ®_num, &shift);
|
||||
|
||||
if (set)
|
||||
setbits32(cmxucr, mask << shift);
|
||||
else
|
||||
clrbits32(cmxucr, mask << shift);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock,
|
||||
enum comm_dir mode)
|
||||
{
|
||||
__be32 __iomem *cmxucr;
|
||||
unsigned int reg_num;
|
||||
unsigned int shift;
|
||||
u32 clock_bits = 0;
|
||||
|
||||
/* check if the UCC number is in range. */
|
||||
if (ucc_num > UCC_MAX_NUM - 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* The communications direction must be RX or TX */
|
||||
if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX)))
|
||||
return -EINVAL;
|
||||
|
||||
get_cmxucr_reg(ucc_num, &cmxucr, ®_num, &shift);
|
||||
|
||||
switch (reg_num) {
|
||||
case 1:
|
||||
switch (clock) {
|
||||
case QE_BRG1: clock_bits = 1; break;
|
||||
case QE_BRG2: clock_bits = 2; break;
|
||||
case QE_BRG7: clock_bits = 3; break;
|
||||
case QE_BRG8: clock_bits = 4; break;
|
||||
case QE_CLK9: clock_bits = 5; break;
|
||||
case QE_CLK10: clock_bits = 6; break;
|
||||
case QE_CLK11: clock_bits = 7; break;
|
||||
case QE_CLK12: clock_bits = 8; break;
|
||||
case QE_CLK15: clock_bits = 9; break;
|
||||
case QE_CLK16: clock_bits = 10; break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (clock) {
|
||||
case QE_BRG5: clock_bits = 1; break;
|
||||
case QE_BRG6: clock_bits = 2; break;
|
||||
case QE_BRG7: clock_bits = 3; break;
|
||||
case QE_BRG8: clock_bits = 4; break;
|
||||
case QE_CLK13: clock_bits = 5; break;
|
||||
case QE_CLK14: clock_bits = 6; break;
|
||||
case QE_CLK19: clock_bits = 7; break;
|
||||
case QE_CLK20: clock_bits = 8; break;
|
||||
case QE_CLK15: clock_bits = 9; break;
|
||||
case QE_CLK16: clock_bits = 10; break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (clock) {
|
||||
case QE_BRG9: clock_bits = 1; break;
|
||||
case QE_BRG10: clock_bits = 2; break;
|
||||
case QE_BRG15: clock_bits = 3; break;
|
||||
case QE_BRG16: clock_bits = 4; break;
|
||||
case QE_CLK3: clock_bits = 5; break;
|
||||
case QE_CLK4: clock_bits = 6; break;
|
||||
case QE_CLK17: clock_bits = 7; break;
|
||||
case QE_CLK18: clock_bits = 8; break;
|
||||
case QE_CLK7: clock_bits = 9; break;
|
||||
case QE_CLK8: clock_bits = 10; break;
|
||||
case QE_CLK16: clock_bits = 11; break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (clock) {
|
||||
case QE_BRG13: clock_bits = 1; break;
|
||||
case QE_BRG14: clock_bits = 2; break;
|
||||
case QE_BRG15: clock_bits = 3; break;
|
||||
case QE_BRG16: clock_bits = 4; break;
|
||||
case QE_CLK5: clock_bits = 5; break;
|
||||
case QE_CLK6: clock_bits = 6; break;
|
||||
case QE_CLK21: clock_bits = 7; break;
|
||||
case QE_CLK22: clock_bits = 8; break;
|
||||
case QE_CLK7: clock_bits = 9; break;
|
||||
case QE_CLK8: clock_bits = 10; break;
|
||||
case QE_CLK16: clock_bits = 11; break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
/* Check for invalid combination of clock and UCC number */
|
||||
if (!clock_bits)
|
||||
return -ENOENT;
|
||||
|
||||
if (mode == COMM_DIR_RX)
|
||||
shift += 4;
|
||||
|
||||
clrsetbits_be32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift,
|
||||
clock_bits << shift);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Authors: Shlomi Gridish <gridish@freescale.com>
|
||||
* Li Yang <leoli@freescale.com>
|
||||
*
|
||||
* Description:
|
||||
* QE UCC Fast API Set - UCC Fast specific routines implementations.
|
||||
*
|
||||
* 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/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_qe.h>
|
||||
#include <asm/qe.h>
|
||||
|
||||
#include <asm/ucc.h>
|
||||
#include <asm/ucc_fast.h>
|
||||
|
||||
void ucc_fast_dump_regs(struct ucc_fast_private * uccf)
|
||||
{
|
||||
printk(KERN_INFO "UCC%u Fast registers:\n", uccf->uf_info->ucc_num);
|
||||
printk(KERN_INFO "Base address: 0x%p\n", uccf->uf_regs);
|
||||
|
||||
printk(KERN_INFO "gumr : addr=0x%p, val=0x%08x\n",
|
||||
&uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr));
|
||||
printk(KERN_INFO "upsmr : addr=0x%p, val=0x%08x\n",
|
||||
&uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr));
|
||||
printk(KERN_INFO "utodr : addr=0x%p, val=0x%04x\n",
|
||||
&uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr));
|
||||
printk(KERN_INFO "udsr : addr=0x%p, val=0x%04x\n",
|
||||
&uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr));
|
||||
printk(KERN_INFO "ucce : addr=0x%p, val=0x%08x\n",
|
||||
&uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce));
|
||||
printk(KERN_INFO "uccm : addr=0x%p, val=0x%08x\n",
|
||||
&uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm));
|
||||
printk(KERN_INFO "uccs : addr=0x%p, val=0x%02x\n",
|
||||
&uccf->uf_regs->uccs, in_8(&uccf->uf_regs->uccs));
|
||||
printk(KERN_INFO "urfb : addr=0x%p, val=0x%08x\n",
|
||||
&uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb));
|
||||
printk(KERN_INFO "urfs : addr=0x%p, val=0x%04x\n",
|
||||
&uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs));
|
||||
printk(KERN_INFO "urfet : addr=0x%p, val=0x%04x\n",
|
||||
&uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet));
|
||||
printk(KERN_INFO "urfset: addr=0x%p, val=0x%04x\n",
|
||||
&uccf->uf_regs->urfset, in_be16(&uccf->uf_regs->urfset));
|
||||
printk(KERN_INFO "utfb : addr=0x%p, val=0x%08x\n",
|
||||
&uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb));
|
||||
printk(KERN_INFO "utfs : addr=0x%p, val=0x%04x\n",
|
||||
&uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs));
|
||||
printk(KERN_INFO "utfet : addr=0x%p, val=0x%04x\n",
|
||||
&uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet));
|
||||
printk(KERN_INFO "utftt : addr=0x%p, val=0x%04x\n",
|
||||
&uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt));
|
||||
printk(KERN_INFO "utpt : addr=0x%p, val=0x%04x\n",
|
||||
&uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt));
|
||||
printk(KERN_INFO "urtry : addr=0x%p, val=0x%08x\n",
|
||||
&uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry));
|
||||
printk(KERN_INFO "guemr : addr=0x%p, val=0x%02x\n",
|
||||
&uccf->uf_regs->guemr, in_8(&uccf->uf_regs->guemr));
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_fast_dump_regs);
|
||||
|
||||
u32 ucc_fast_get_qe_cr_subblock(int uccf_num)
|
||||
{
|
||||
switch (uccf_num) {
|
||||
case 0: return QE_CR_SUBBLOCK_UCCFAST1;
|
||||
case 1: return QE_CR_SUBBLOCK_UCCFAST2;
|
||||
case 2: return QE_CR_SUBBLOCK_UCCFAST3;
|
||||
case 3: return QE_CR_SUBBLOCK_UCCFAST4;
|
||||
case 4: return QE_CR_SUBBLOCK_UCCFAST5;
|
||||
case 5: return QE_CR_SUBBLOCK_UCCFAST6;
|
||||
case 6: return QE_CR_SUBBLOCK_UCCFAST7;
|
||||
case 7: return QE_CR_SUBBLOCK_UCCFAST8;
|
||||
default: return QE_CR_SUBBLOCK_INVALID;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_fast_get_qe_cr_subblock);
|
||||
|
||||
void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf)
|
||||
{
|
||||
out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_fast_transmit_on_demand);
|
||||
|
||||
void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode)
|
||||
{
|
||||
struct ucc_fast __iomem *uf_regs;
|
||||
u32 gumr;
|
||||
|
||||
uf_regs = uccf->uf_regs;
|
||||
|
||||
/* Enable reception and/or transmission on this UCC. */
|
||||
gumr = in_be32(&uf_regs->gumr);
|
||||
if (mode & COMM_DIR_TX) {
|
||||
gumr |= UCC_FAST_GUMR_ENT;
|
||||
uccf->enabled_tx = 1;
|
||||
}
|
||||
if (mode & COMM_DIR_RX) {
|
||||
gumr |= UCC_FAST_GUMR_ENR;
|
||||
uccf->enabled_rx = 1;
|
||||
}
|
||||
out_be32(&uf_regs->gumr, gumr);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_fast_enable);
|
||||
|
||||
void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode)
|
||||
{
|
||||
struct ucc_fast __iomem *uf_regs;
|
||||
u32 gumr;
|
||||
|
||||
uf_regs = uccf->uf_regs;
|
||||
|
||||
/* Disable reception and/or transmission on this UCC. */
|
||||
gumr = in_be32(&uf_regs->gumr);
|
||||
if (mode & COMM_DIR_TX) {
|
||||
gumr &= ~UCC_FAST_GUMR_ENT;
|
||||
uccf->enabled_tx = 0;
|
||||
}
|
||||
if (mode & COMM_DIR_RX) {
|
||||
gumr &= ~UCC_FAST_GUMR_ENR;
|
||||
uccf->enabled_rx = 0;
|
||||
}
|
||||
out_be32(&uf_regs->gumr, gumr);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_fast_disable);
|
||||
|
||||
int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret)
|
||||
{
|
||||
struct ucc_fast_private *uccf;
|
||||
struct ucc_fast __iomem *uf_regs;
|
||||
u32 gumr;
|
||||
int ret;
|
||||
|
||||
if (!uf_info)
|
||||
return -EINVAL;
|
||||
|
||||
/* check if the UCC port number is in range. */
|
||||
if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) {
|
||||
printk(KERN_ERR "%s: illegal UCC number\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check that 'max_rx_buf_length' is properly aligned (4). */
|
||||
if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) {
|
||||
printk(KERN_ERR "%s: max_rx_buf_length not aligned\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Validate Virtual Fifo register values */
|
||||
if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) {
|
||||
printk(KERN_ERR "%s: urfs is too small\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
|
||||
printk(KERN_ERR "%s: urfs is not aligned\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
|
||||
printk(KERN_ERR "%s: urfet is not aligned.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
|
||||
printk(KERN_ERR "%s: urfset is not aligned\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
|
||||
printk(KERN_ERR "%s: utfs is not aligned\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
|
||||
printk(KERN_ERR "%s: utfet is not aligned\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
|
||||
printk(KERN_ERR "%s: utftt is not aligned\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uccf = kzalloc(sizeof(struct ucc_fast_private), GFP_KERNEL);
|
||||
if (!uccf) {
|
||||
printk(KERN_ERR "%s: Cannot allocate private data\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Fill fast UCC structure */
|
||||
uccf->uf_info = uf_info;
|
||||
/* Set the PHY base address */
|
||||
uccf->uf_regs = ioremap(uf_info->regs, sizeof(struct ucc_fast));
|
||||
if (uccf->uf_regs == NULL) {
|
||||
printk(KERN_ERR "%s: Cannot map UCC registers\n", __func__);
|
||||
kfree(uccf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
uccf->enabled_tx = 0;
|
||||
uccf->enabled_rx = 0;
|
||||
uccf->stopped_tx = 0;
|
||||
uccf->stopped_rx = 0;
|
||||
uf_regs = uccf->uf_regs;
|
||||
uccf->p_ucce = &uf_regs->ucce;
|
||||
uccf->p_uccm = &uf_regs->uccm;
|
||||
#ifdef CONFIG_UGETH_TX_ON_DEMAND
|
||||
uccf->p_utodr = &uf_regs->utodr;
|
||||
#endif
|
||||
#ifdef STATISTICS
|
||||
uccf->tx_frames = 0;
|
||||
uccf->rx_frames = 0;
|
||||
uccf->rx_discarded = 0;
|
||||
#endif /* STATISTICS */
|
||||
|
||||
/* Set UCC to fast type */
|
||||
ret = ucc_set_type(uf_info->ucc_num, UCC_SPEED_TYPE_FAST);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: cannot set UCC type\n", __func__);
|
||||
ucc_fast_free(uccf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uccf->mrblr = uf_info->max_rx_buf_length;
|
||||
|
||||
/* Set GUMR */
|
||||
/* For more details see the hardware spec. */
|
||||
gumr = uf_info->ttx_trx;
|
||||
if (uf_info->tci)
|
||||
gumr |= UCC_FAST_GUMR_TCI;
|
||||
if (uf_info->cdp)
|
||||
gumr |= UCC_FAST_GUMR_CDP;
|
||||
if (uf_info->ctsp)
|
||||
gumr |= UCC_FAST_GUMR_CTSP;
|
||||
if (uf_info->cds)
|
||||
gumr |= UCC_FAST_GUMR_CDS;
|
||||
if (uf_info->ctss)
|
||||
gumr |= UCC_FAST_GUMR_CTSS;
|
||||
if (uf_info->txsy)
|
||||
gumr |= UCC_FAST_GUMR_TXSY;
|
||||
if (uf_info->rsyn)
|
||||
gumr |= UCC_FAST_GUMR_RSYN;
|
||||
gumr |= uf_info->synl;
|
||||
if (uf_info->rtsm)
|
||||
gumr |= UCC_FAST_GUMR_RTSM;
|
||||
gumr |= uf_info->renc;
|
||||
if (uf_info->revd)
|
||||
gumr |= UCC_FAST_GUMR_REVD;
|
||||
gumr |= uf_info->tenc;
|
||||
gumr |= uf_info->tcrc;
|
||||
gumr |= uf_info->mode;
|
||||
out_be32(&uf_regs->gumr, gumr);
|
||||
|
||||
/* Allocate memory for Tx Virtual Fifo */
|
||||
uccf->ucc_fast_tx_virtual_fifo_base_offset =
|
||||
qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
|
||||
if (IS_ERR_VALUE(uccf->ucc_fast_tx_virtual_fifo_base_offset)) {
|
||||
printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO\n",
|
||||
__func__);
|
||||
uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
|
||||
ucc_fast_free(uccf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Allocate memory for Rx Virtual Fifo */
|
||||
uccf->ucc_fast_rx_virtual_fifo_base_offset =
|
||||
qe_muram_alloc(uf_info->urfs +
|
||||
UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR,
|
||||
UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
|
||||
if (IS_ERR_VALUE(uccf->ucc_fast_rx_virtual_fifo_base_offset)) {
|
||||
printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO\n",
|
||||
__func__);
|
||||
uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
|
||||
ucc_fast_free(uccf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set Virtual Fifo registers */
|
||||
out_be16(&uf_regs->urfs, uf_info->urfs);
|
||||
out_be16(&uf_regs->urfet, uf_info->urfet);
|
||||
out_be16(&uf_regs->urfset, uf_info->urfset);
|
||||
out_be16(&uf_regs->utfs, uf_info->utfs);
|
||||
out_be16(&uf_regs->utfet, uf_info->utfet);
|
||||
out_be16(&uf_regs->utftt, uf_info->utftt);
|
||||
/* utfb, urfb are offsets from MURAM base */
|
||||
out_be32(&uf_regs->utfb, uccf->ucc_fast_tx_virtual_fifo_base_offset);
|
||||
out_be32(&uf_regs->urfb, uccf->ucc_fast_rx_virtual_fifo_base_offset);
|
||||
|
||||
/* Mux clocking */
|
||||
/* Grant Support */
|
||||
ucc_set_qe_mux_grant(uf_info->ucc_num, uf_info->grant_support);
|
||||
/* Breakpoint Support */
|
||||
ucc_set_qe_mux_bkpt(uf_info->ucc_num, uf_info->brkpt_support);
|
||||
/* Set Tsa or NMSI mode. */
|
||||
ucc_set_qe_mux_tsa(uf_info->ucc_num, uf_info->tsa);
|
||||
/* If NMSI (not Tsa), set Tx and Rx clock. */
|
||||
if (!uf_info->tsa) {
|
||||
/* Rx clock routing */
|
||||
if ((uf_info->rx_clock != QE_CLK_NONE) &&
|
||||
ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->rx_clock,
|
||||
COMM_DIR_RX)) {
|
||||
printk(KERN_ERR "%s: illegal value for RX clock\n",
|
||||
__func__);
|
||||
ucc_fast_free(uccf);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Tx clock routing */
|
||||
if ((uf_info->tx_clock != QE_CLK_NONE) &&
|
||||
ucc_set_qe_mux_rxtx(uf_info->ucc_num, uf_info->tx_clock,
|
||||
COMM_DIR_TX)) {
|
||||
printk(KERN_ERR "%s: illegal value for TX clock\n",
|
||||
__func__);
|
||||
ucc_fast_free(uccf);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set interrupt mask register at UCC level. */
|
||||
out_be32(&uf_regs->uccm, uf_info->uccm_mask);
|
||||
|
||||
/* First, clear anything pending at UCC level,
|
||||
* otherwise, old garbage may come through
|
||||
* as soon as the dam is opened. */
|
||||
|
||||
/* Writing '1' clears */
|
||||
out_be32(&uf_regs->ucce, 0xffffffff);
|
||||
|
||||
*uccf_ret = uccf;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_fast_init);
|
||||
|
||||
void ucc_fast_free(struct ucc_fast_private * uccf)
|
||||
{
|
||||
if (!uccf)
|
||||
return;
|
||||
|
||||
if (uccf->ucc_fast_tx_virtual_fifo_base_offset)
|
||||
qe_muram_free(uccf->ucc_fast_tx_virtual_fifo_base_offset);
|
||||
|
||||
if (uccf->ucc_fast_rx_virtual_fifo_base_offset)
|
||||
qe_muram_free(uccf->ucc_fast_rx_virtual_fifo_base_offset);
|
||||
|
||||
if (uccf->uf_regs)
|
||||
iounmap(uccf->uf_regs);
|
||||
|
||||
kfree(uccf);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_fast_free);
|
||||
@@ -1,374 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Authors: Shlomi Gridish <gridish@freescale.com>
|
||||
* Li Yang <leoli@freescale.com>
|
||||
*
|
||||
* Description:
|
||||
* QE UCC Slow API Set - UCC Slow specific routines implementations.
|
||||
*
|
||||
* 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/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/immap_qe.h>
|
||||
#include <asm/qe.h>
|
||||
|
||||
#include <asm/ucc.h>
|
||||
#include <asm/ucc_slow.h>
|
||||
|
||||
u32 ucc_slow_get_qe_cr_subblock(int uccs_num)
|
||||
{
|
||||
switch (uccs_num) {
|
||||
case 0: return QE_CR_SUBBLOCK_UCCSLOW1;
|
||||
case 1: return QE_CR_SUBBLOCK_UCCSLOW2;
|
||||
case 2: return QE_CR_SUBBLOCK_UCCSLOW3;
|
||||
case 3: return QE_CR_SUBBLOCK_UCCSLOW4;
|
||||
case 4: return QE_CR_SUBBLOCK_UCCSLOW5;
|
||||
case 5: return QE_CR_SUBBLOCK_UCCSLOW6;
|
||||
case 6: return QE_CR_SUBBLOCK_UCCSLOW7;
|
||||
case 7: return QE_CR_SUBBLOCK_UCCSLOW8;
|
||||
default: return QE_CR_SUBBLOCK_INVALID;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_slow_get_qe_cr_subblock);
|
||||
|
||||
void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs)
|
||||
{
|
||||
struct ucc_slow_info *us_info = uccs->us_info;
|
||||
u32 id;
|
||||
|
||||
id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
|
||||
qe_issue_cmd(QE_GRACEFUL_STOP_TX, id,
|
||||
QE_CR_PROTOCOL_UNSPECIFIED, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_slow_graceful_stop_tx);
|
||||
|
||||
void ucc_slow_stop_tx(struct ucc_slow_private * uccs)
|
||||
{
|
||||
struct ucc_slow_info *us_info = uccs->us_info;
|
||||
u32 id;
|
||||
|
||||
id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
|
||||
qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_slow_stop_tx);
|
||||
|
||||
void ucc_slow_restart_tx(struct ucc_slow_private * uccs)
|
||||
{
|
||||
struct ucc_slow_info *us_info = uccs->us_info;
|
||||
u32 id;
|
||||
|
||||
id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
|
||||
qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_slow_restart_tx);
|
||||
|
||||
void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode)
|
||||
{
|
||||
struct ucc_slow *us_regs;
|
||||
u32 gumr_l;
|
||||
|
||||
us_regs = uccs->us_regs;
|
||||
|
||||
/* Enable reception and/or transmission on this UCC. */
|
||||
gumr_l = in_be32(&us_regs->gumr_l);
|
||||
if (mode & COMM_DIR_TX) {
|
||||
gumr_l |= UCC_SLOW_GUMR_L_ENT;
|
||||
uccs->enabled_tx = 1;
|
||||
}
|
||||
if (mode & COMM_DIR_RX) {
|
||||
gumr_l |= UCC_SLOW_GUMR_L_ENR;
|
||||
uccs->enabled_rx = 1;
|
||||
}
|
||||
out_be32(&us_regs->gumr_l, gumr_l);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_slow_enable);
|
||||
|
||||
void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode)
|
||||
{
|
||||
struct ucc_slow *us_regs;
|
||||
u32 gumr_l;
|
||||
|
||||
us_regs = uccs->us_regs;
|
||||
|
||||
/* Disable reception and/or transmission on this UCC. */
|
||||
gumr_l = in_be32(&us_regs->gumr_l);
|
||||
if (mode & COMM_DIR_TX) {
|
||||
gumr_l &= ~UCC_SLOW_GUMR_L_ENT;
|
||||
uccs->enabled_tx = 0;
|
||||
}
|
||||
if (mode & COMM_DIR_RX) {
|
||||
gumr_l &= ~UCC_SLOW_GUMR_L_ENR;
|
||||
uccs->enabled_rx = 0;
|
||||
}
|
||||
out_be32(&us_regs->gumr_l, gumr_l);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_slow_disable);
|
||||
|
||||
/* Initialize the UCC for Slow operations
|
||||
*
|
||||
* The caller should initialize the following us_info
|
||||
*/
|
||||
int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret)
|
||||
{
|
||||
struct ucc_slow_private *uccs;
|
||||
u32 i;
|
||||
struct ucc_slow __iomem *us_regs;
|
||||
u32 gumr;
|
||||
struct qe_bd *bd;
|
||||
u32 id;
|
||||
u32 command;
|
||||
int ret = 0;
|
||||
|
||||
if (!us_info)
|
||||
return -EINVAL;
|
||||
|
||||
/* check if the UCC port number is in range. */
|
||||
if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) {
|
||||
printk(KERN_ERR "%s: illegal UCC number\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set mrblr
|
||||
* Check that 'max_rx_buf_length' is properly aligned (4), unless
|
||||
* rfw is 1, meaning that QE accepts one byte at a time, unlike normal
|
||||
* case when QE accepts 32 bits at a time.
|
||||
*/
|
||||
if ((!us_info->rfw) &&
|
||||
(us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) {
|
||||
printk(KERN_ERR "max_rx_buf_length not aligned.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uccs = kzalloc(sizeof(struct ucc_slow_private), GFP_KERNEL);
|
||||
if (!uccs) {
|
||||
printk(KERN_ERR "%s: Cannot allocate private data\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Fill slow UCC structure */
|
||||
uccs->us_info = us_info;
|
||||
/* Set the PHY base address */
|
||||
uccs->us_regs = ioremap(us_info->regs, sizeof(struct ucc_slow));
|
||||
if (uccs->us_regs == NULL) {
|
||||
printk(KERN_ERR "%s: Cannot map UCC registers\n", __func__);
|
||||
kfree(uccs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
uccs->saved_uccm = 0;
|
||||
uccs->p_rx_frame = 0;
|
||||
us_regs = uccs->us_regs;
|
||||
uccs->p_ucce = (u16 *) & (us_regs->ucce);
|
||||
uccs->p_uccm = (u16 *) & (us_regs->uccm);
|
||||
#ifdef STATISTICS
|
||||
uccs->rx_frames = 0;
|
||||
uccs->tx_frames = 0;
|
||||
uccs->rx_discarded = 0;
|
||||
#endif /* STATISTICS */
|
||||
|
||||
/* Get PRAM base */
|
||||
uccs->us_pram_offset =
|
||||
qe_muram_alloc(UCC_SLOW_PRAM_SIZE, ALIGNMENT_OF_UCC_SLOW_PRAM);
|
||||
if (IS_ERR_VALUE(uccs->us_pram_offset)) {
|
||||
printk(KERN_ERR "%s: cannot allocate MURAM for PRAM", __func__);
|
||||
ucc_slow_free(uccs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
|
||||
qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, us_info->protocol,
|
||||
uccs->us_pram_offset);
|
||||
|
||||
uccs->us_pram = qe_muram_addr(uccs->us_pram_offset);
|
||||
|
||||
/* Set UCC to slow type */
|
||||
ret = ucc_set_type(us_info->ucc_num, UCC_SPEED_TYPE_SLOW);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: cannot set UCC type", __func__);
|
||||
ucc_slow_free(uccs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
out_be16(&uccs->us_pram->mrblr, us_info->max_rx_buf_length);
|
||||
|
||||
INIT_LIST_HEAD(&uccs->confQ);
|
||||
|
||||
/* Allocate BDs. */
|
||||
uccs->rx_base_offset =
|
||||
qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd),
|
||||
QE_ALIGNMENT_OF_BD);
|
||||
if (IS_ERR_VALUE(uccs->rx_base_offset)) {
|
||||
printk(KERN_ERR "%s: cannot allocate %u RX BDs\n", __func__,
|
||||
us_info->rx_bd_ring_len);
|
||||
uccs->rx_base_offset = 0;
|
||||
ucc_slow_free(uccs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
uccs->tx_base_offset =
|
||||
qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd),
|
||||
QE_ALIGNMENT_OF_BD);
|
||||
if (IS_ERR_VALUE(uccs->tx_base_offset)) {
|
||||
printk(KERN_ERR "%s: cannot allocate TX BDs", __func__);
|
||||
uccs->tx_base_offset = 0;
|
||||
ucc_slow_free(uccs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Init Tx bds */
|
||||
bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset);
|
||||
for (i = 0; i < us_info->tx_bd_ring_len - 1; i++) {
|
||||
/* clear bd buffer */
|
||||
out_be32(&bd->buf, 0);
|
||||
/* set bd status and length */
|
||||
out_be32((u32 *) bd, 0);
|
||||
bd++;
|
||||
}
|
||||
/* for last BD set Wrap bit */
|
||||
out_be32(&bd->buf, 0);
|
||||
out_be32((u32 *) bd, cpu_to_be32(T_W));
|
||||
|
||||
/* Init Rx bds */
|
||||
bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset);
|
||||
for (i = 0; i < us_info->rx_bd_ring_len - 1; i++) {
|
||||
/* set bd status and length */
|
||||
out_be32((u32*)bd, 0);
|
||||
/* clear bd buffer */
|
||||
out_be32(&bd->buf, 0);
|
||||
bd++;
|
||||
}
|
||||
/* for last BD set Wrap bit */
|
||||
out_be32((u32*)bd, cpu_to_be32(R_W));
|
||||
out_be32(&bd->buf, 0);
|
||||
|
||||
/* Set GUMR (For more details see the hardware spec.). */
|
||||
/* gumr_h */
|
||||
gumr = us_info->tcrc;
|
||||
if (us_info->cdp)
|
||||
gumr |= UCC_SLOW_GUMR_H_CDP;
|
||||
if (us_info->ctsp)
|
||||
gumr |= UCC_SLOW_GUMR_H_CTSP;
|
||||
if (us_info->cds)
|
||||
gumr |= UCC_SLOW_GUMR_H_CDS;
|
||||
if (us_info->ctss)
|
||||
gumr |= UCC_SLOW_GUMR_H_CTSS;
|
||||
if (us_info->tfl)
|
||||
gumr |= UCC_SLOW_GUMR_H_TFL;
|
||||
if (us_info->rfw)
|
||||
gumr |= UCC_SLOW_GUMR_H_RFW;
|
||||
if (us_info->txsy)
|
||||
gumr |= UCC_SLOW_GUMR_H_TXSY;
|
||||
if (us_info->rtsm)
|
||||
gumr |= UCC_SLOW_GUMR_H_RTSM;
|
||||
out_be32(&us_regs->gumr_h, gumr);
|
||||
|
||||
/* gumr_l */
|
||||
gumr = us_info->tdcr | us_info->rdcr | us_info->tenc | us_info->renc |
|
||||
us_info->diag | us_info->mode;
|
||||
if (us_info->tci)
|
||||
gumr |= UCC_SLOW_GUMR_L_TCI;
|
||||
if (us_info->rinv)
|
||||
gumr |= UCC_SLOW_GUMR_L_RINV;
|
||||
if (us_info->tinv)
|
||||
gumr |= UCC_SLOW_GUMR_L_TINV;
|
||||
if (us_info->tend)
|
||||
gumr |= UCC_SLOW_GUMR_L_TEND;
|
||||
out_be32(&us_regs->gumr_l, gumr);
|
||||
|
||||
/* Function code registers */
|
||||
|
||||
/* if the data is in cachable memory, the 'global' */
|
||||
/* in the function code should be set. */
|
||||
uccs->us_pram->tbmr = UCC_BMR_BO_BE;
|
||||
uccs->us_pram->rbmr = UCC_BMR_BO_BE;
|
||||
|
||||
/* rbase, tbase are offsets from MURAM base */
|
||||
out_be16(&uccs->us_pram->rbase, uccs->rx_base_offset);
|
||||
out_be16(&uccs->us_pram->tbase, uccs->tx_base_offset);
|
||||
|
||||
/* Mux clocking */
|
||||
/* Grant Support */
|
||||
ucc_set_qe_mux_grant(us_info->ucc_num, us_info->grant_support);
|
||||
/* Breakpoint Support */
|
||||
ucc_set_qe_mux_bkpt(us_info->ucc_num, us_info->brkpt_support);
|
||||
/* Set Tsa or NMSI mode. */
|
||||
ucc_set_qe_mux_tsa(us_info->ucc_num, us_info->tsa);
|
||||
/* If NMSI (not Tsa), set Tx and Rx clock. */
|
||||
if (!us_info->tsa) {
|
||||
/* Rx clock routing */
|
||||
if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->rx_clock,
|
||||
COMM_DIR_RX)) {
|
||||
printk(KERN_ERR "%s: illegal value for RX clock\n",
|
||||
__func__);
|
||||
ucc_slow_free(uccs);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Tx clock routing */
|
||||
if (ucc_set_qe_mux_rxtx(us_info->ucc_num, us_info->tx_clock,
|
||||
COMM_DIR_TX)) {
|
||||
printk(KERN_ERR "%s: illegal value for TX clock\n",
|
||||
__func__);
|
||||
ucc_slow_free(uccs);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set interrupt mask register at UCC level. */
|
||||
out_be16(&us_regs->uccm, us_info->uccm_mask);
|
||||
|
||||
/* First, clear anything pending at UCC level,
|
||||
* otherwise, old garbage may come through
|
||||
* as soon as the dam is opened. */
|
||||
|
||||
/* Writing '1' clears */
|
||||
out_be16(&us_regs->ucce, 0xffff);
|
||||
|
||||
/* Issue QE Init command */
|
||||
if (us_info->init_tx && us_info->init_rx)
|
||||
command = QE_INIT_TX_RX;
|
||||
else if (us_info->init_tx)
|
||||
command = QE_INIT_TX;
|
||||
else
|
||||
command = QE_INIT_RX; /* We know at least one is TRUE */
|
||||
|
||||
qe_issue_cmd(command, id, us_info->protocol, 0);
|
||||
|
||||
*uccs_ret = uccs;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_slow_init);
|
||||
|
||||
void ucc_slow_free(struct ucc_slow_private * uccs)
|
||||
{
|
||||
if (!uccs)
|
||||
return;
|
||||
|
||||
if (uccs->rx_base_offset)
|
||||
qe_muram_free(uccs->rx_base_offset);
|
||||
|
||||
if (uccs->tx_base_offset)
|
||||
qe_muram_free(uccs->tx_base_offset);
|
||||
|
||||
if (uccs->us_pram)
|
||||
qe_muram_free(uccs->us_pram_offset);
|
||||
|
||||
if (uccs->us_regs)
|
||||
iounmap(uccs->us_regs);
|
||||
|
||||
kfree(uccs);
|
||||
}
|
||||
EXPORT_SYMBOL(ucc_slow_free);
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* QE USB routines
|
||||
*
|
||||
* Copyright 2006 Freescale Semiconductor, Inc.
|
||||
* Shlomi Gridish <gridish@freescale.com>
|
||||
* Jerry Huang <Chang-Ming.Huang@freescale.com>
|
||||
* Copyright (c) MontaVista Software, Inc. 2008.
|
||||
* Anton Vorontsov <avorontsov@ru.mvista.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/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/immap_qe.h>
|
||||
#include <asm/qe.h>
|
||||
|
||||
int qe_usb_clock_set(enum qe_clock clk, int rate)
|
||||
{
|
||||
struct qe_mux __iomem *mux = &qe_immr->qmx;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
switch (clk) {
|
||||
case QE_CLK3: val = QE_CMXGCR_USBCS_CLK3; break;
|
||||
case QE_CLK5: val = QE_CMXGCR_USBCS_CLK5; break;
|
||||
case QE_CLK7: val = QE_CMXGCR_USBCS_CLK7; break;
|
||||
case QE_CLK9: val = QE_CMXGCR_USBCS_CLK9; break;
|
||||
case QE_CLK13: val = QE_CMXGCR_USBCS_CLK13; break;
|
||||
case QE_CLK17: val = QE_CMXGCR_USBCS_CLK17; break;
|
||||
case QE_CLK19: val = QE_CMXGCR_USBCS_CLK19; break;
|
||||
case QE_CLK21: val = QE_CMXGCR_USBCS_CLK21; break;
|
||||
case QE_BRG9: val = QE_CMXGCR_USBCS_BRG9; break;
|
||||
case QE_BRG10: val = QE_CMXGCR_USBCS_BRG10; break;
|
||||
default:
|
||||
pr_err("%s: requested unknown clock %d\n", __func__, clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (qe_clock_is_brg(clk))
|
||||
qe_setbrg(clk, rate, 1);
|
||||
|
||||
spin_lock_irqsave(&cmxgcr_lock, flags);
|
||||
|
||||
clrsetbits_be32(&mux->cmxgcr, QE_CMXGCR_USBCS, val);
|
||||
|
||||
spin_unlock_irqrestore(&cmxgcr_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qe_usb_clock_set);
|
||||
Reference in New Issue
Block a user