2007-09-16 18:53:27 +08:00
|
|
|
/*
|
|
|
|
* Driver for MPC52xx processor BestComm peripheral controller
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
|
|
|
|
* Copyright (C) 2005 Varma Electronics Oy,
|
|
|
|
* ( by Andrey Volkov <avolkov@varma-el.com> )
|
|
|
|
* Copyright (C) 2003-2004 MontaVista, Software, Inc.
|
|
|
|
* ( by Dale Farnsworth <dfarnsworth@mvista.com> )
|
|
|
|
*
|
|
|
|
* This file is licensed under the terms of the GNU General Public License
|
|
|
|
* version 2. This program is licensed "as is" without any warranty of any
|
|
|
|
* kind, whether express or implied.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/of_device.h>
|
|
|
|
#include <linux/of_platform.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/irq.h>
|
|
|
|
#include <asm/mpc52xx.h>
|
|
|
|
|
2012-10-12 23:52:45 +08:00
|
|
|
#include <linux/fsl/bestcomm/sram.h>
|
|
|
|
#include <linux/fsl/bestcomm/bestcomm_priv.h>
|
|
|
|
#include "linux/fsl/bestcomm/bestcomm.h"
|
2007-09-16 18:53:27 +08:00
|
|
|
|
|
|
|
#define DRIVER_NAME "bestcomm-core"
|
|
|
|
|
2008-01-25 13:25:31 +08:00
|
|
|
/* MPC5200 device tree match tables */
|
2015-03-17 03:17:14 +08:00
|
|
|
static const struct of_device_id mpc52xx_sram_ids[] = {
|
2008-01-25 13:25:31 +08:00
|
|
|
{ .compatible = "fsl,mpc5200-sram", },
|
|
|
|
{ .compatible = "mpc5200-sram", },
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2007-09-16 18:53:27 +08:00
|
|
|
|
|
|
|
struct bcom_engine *bcom_eng = NULL;
|
|
|
|
EXPORT_SYMBOL_GPL(bcom_eng); /* needed for inline functions */
|
|
|
|
|
|
|
|
/* ======================================================================== */
|
|
|
|
/* Public and private API */
|
|
|
|
/* ======================================================================== */
|
|
|
|
|
|
|
|
/* Private API */
|
|
|
|
|
|
|
|
struct bcom_task *
|
|
|
|
bcom_task_alloc(int bd_count, int bd_size, int priv_size)
|
|
|
|
{
|
|
|
|
int i, tasknum = -1;
|
|
|
|
struct bcom_task *tsk;
|
|
|
|
|
2008-03-22 11:41:05 +08:00
|
|
|
/* Don't try to do anything if bestcomm init failed */
|
|
|
|
if (!bcom_eng)
|
|
|
|
return NULL;
|
|
|
|
|
2007-09-16 18:53:27 +08:00
|
|
|
/* Get and reserve a task num */
|
|
|
|
spin_lock(&bcom_eng->lock);
|
|
|
|
|
|
|
|
for (i=0; i<BCOM_MAX_TASKS; i++)
|
|
|
|
if (!bcom_eng->tdt[i].stop) { /* we use stop as a marker */
|
|
|
|
bcom_eng->tdt[i].stop = 0xfffffffful; /* dummy addr */
|
|
|
|
tasknum = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock(&bcom_eng->lock);
|
|
|
|
|
|
|
|
if (tasknum < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Allocate our structure */
|
|
|
|
tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL);
|
|
|
|
if (!tsk)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
tsk->tasknum = tasknum;
|
|
|
|
if (priv_size)
|
|
|
|
tsk->priv = (void*)tsk + sizeof(struct bcom_task);
|
|
|
|
|
|
|
|
/* Get IRQ of that task */
|
|
|
|
tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum);
|
2016-09-10 17:56:04 +08:00
|
|
|
if (!tsk->irq)
|
2007-09-16 18:53:27 +08:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* Init the BDs, if needed */
|
|
|
|
if (bd_count) {
|
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 04:55:00 +08:00
|
|
|
tsk->cookie = kmalloc_array(bd_count, sizeof(void *),
|
|
|
|
GFP_KERNEL);
|
2007-09-16 18:53:27 +08:00
|
|
|
if (!tsk->cookie)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa);
|
|
|
|
if (!tsk->bd)
|
|
|
|
goto error;
|
|
|
|
memset(tsk->bd, 0x00, bd_count * bd_size);
|
|
|
|
|
|
|
|
tsk->num_bd = bd_count;
|
|
|
|
tsk->bd_size = bd_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tsk;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (tsk) {
|
2016-09-10 17:56:04 +08:00
|
|
|
if (tsk->irq)
|
2007-09-16 18:53:27 +08:00
|
|
|
irq_dispose_mapping(tsk->irq);
|
|
|
|
bcom_sram_free(tsk->bd);
|
|
|
|
kfree(tsk->cookie);
|
|
|
|
kfree(tsk);
|
|
|
|
}
|
|
|
|
|
|
|
|
bcom_eng->tdt[tasknum].stop = 0;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(bcom_task_alloc);
|
|
|
|
|
|
|
|
void
|
|
|
|
bcom_task_free(struct bcom_task *tsk)
|
|
|
|
{
|
|
|
|
/* Stop the task */
|
|
|
|
bcom_disable_task(tsk->tasknum);
|
|
|
|
|
|
|
|
/* Clear TDT */
|
|
|
|
bcom_eng->tdt[tsk->tasknum].start = 0;
|
|
|
|
bcom_eng->tdt[tsk->tasknum].stop = 0;
|
|
|
|
|
|
|
|
/* Free everything */
|
|
|
|
irq_dispose_mapping(tsk->irq);
|
|
|
|
bcom_sram_free(tsk->bd);
|
|
|
|
kfree(tsk->cookie);
|
|
|
|
kfree(tsk);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(bcom_task_free);
|
|
|
|
|
|
|
|
int
|
|
|
|
bcom_load_image(int task, u32 *task_image)
|
|
|
|
{
|
|
|
|
struct bcom_task_header *hdr = (struct bcom_task_header *)task_image;
|
|
|
|
struct bcom_tdt *tdt;
|
|
|
|
u32 *desc, *var, *inc;
|
|
|
|
u32 *desc_src, *var_src, *inc_src;
|
|
|
|
|
|
|
|
/* Safety checks */
|
|
|
|
if (hdr->magic != BCOM_TASK_MAGIC) {
|
|
|
|
printk(KERN_ERR DRIVER_NAME
|
|
|
|
": Trying to load invalid microcode\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((task < 0) || (task >= BCOM_MAX_TASKS)) {
|
|
|
|
printk(KERN_ERR DRIVER_NAME
|
|
|
|
": Trying to load invalid task %d\n", task);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initial load or reload */
|
|
|
|
tdt = &bcom_eng->tdt[task];
|
|
|
|
|
|
|
|
if (tdt->start) {
|
|
|
|
desc = bcom_task_desc(task);
|
|
|
|
if (hdr->desc_size != bcom_task_num_descs(task)) {
|
|
|
|
printk(KERN_ERR DRIVER_NAME
|
|
|
|
": Trying to reload wrong task image "
|
|
|
|
"(%d size %d/%d)!\n",
|
|
|
|
task,
|
|
|
|
hdr->desc_size,
|
|
|
|
bcom_task_num_descs(task));
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
phys_addr_t start_pa;
|
|
|
|
|
|
|
|
desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa);
|
|
|
|
if (!desc)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
tdt->start = start_pa;
|
|
|
|
tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32));
|
|
|
|
}
|
|
|
|
|
|
|
|
var = bcom_task_var(task);
|
|
|
|
inc = bcom_task_inc(task);
|
|
|
|
|
|
|
|
/* Clear & copy */
|
|
|
|
memset(var, 0x00, BCOM_VAR_SIZE);
|
|
|
|
memset(inc, 0x00, BCOM_INC_SIZE);
|
|
|
|
|
|
|
|
desc_src = (u32 *)(hdr + 1);
|
|
|
|
var_src = desc_src + hdr->desc_size;
|
|
|
|
inc_src = var_src + hdr->var_size;
|
|
|
|
|
|
|
|
memcpy(desc, desc_src, hdr->desc_size * sizeof(u32));
|
|
|
|
memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32));
|
|
|
|
memcpy(inc, inc_src, hdr->inc_size * sizeof(u32));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(bcom_load_image);
|
|
|
|
|
|
|
|
void
|
|
|
|
bcom_set_initiator(int task, int initiator)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int num_descs;
|
|
|
|
u32 *desc;
|
|
|
|
int next_drd_has_initiator;
|
|
|
|
|
|
|
|
bcom_set_tcr_initiator(task, initiator);
|
|
|
|
|
|
|
|
/* Just setting tcr is apparently not enough due to some problem */
|
|
|
|
/* with it. So we just go thru all the microcode and replace in */
|
|
|
|
/* the DRD directly */
|
|
|
|
|
|
|
|
desc = bcom_task_desc(task);
|
|
|
|
next_drd_has_initiator = 1;
|
|
|
|
num_descs = bcom_task_num_descs(task);
|
|
|
|
|
|
|
|
for (i=0; i<num_descs; i++, desc++) {
|
|
|
|
if (!bcom_desc_is_drd(*desc))
|
|
|
|
continue;
|
|
|
|
if (next_drd_has_initiator)
|
|
|
|
if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS)
|
|
|
|
bcom_set_desc_initiator(desc, initiator);
|
|
|
|
next_drd_has_initiator = !bcom_drd_is_extended(*desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(bcom_set_initiator);
|
|
|
|
|
|
|
|
|
|
|
|
/* Public API */
|
|
|
|
|
|
|
|
void
|
|
|
|
bcom_enable(struct bcom_task *tsk)
|
|
|
|
{
|
|
|
|
bcom_enable_task(tsk->tasknum);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(bcom_enable);
|
|
|
|
|
|
|
|
void
|
|
|
|
bcom_disable(struct bcom_task *tsk)
|
|
|
|
{
|
|
|
|
bcom_disable_task(tsk->tasknum);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(bcom_disable);
|
|
|
|
|
|
|
|
|
|
|
|
/* ======================================================================== */
|
|
|
|
/* Engine init/cleanup */
|
|
|
|
/* ======================================================================== */
|
|
|
|
|
|
|
|
/* Function Descriptor table */
|
|
|
|
/* this will need to be updated if Freescale changes their task code FDT */
|
|
|
|
static u32 fdt_ops[] = {
|
|
|
|
0xa0045670, /* FDT[48] - load_acc() */
|
|
|
|
0x80045670, /* FDT[49] - unload_acc() */
|
|
|
|
0x21800000, /* FDT[50] - and() */
|
|
|
|
0x21e00000, /* FDT[51] - or() */
|
|
|
|
0x21500000, /* FDT[52] - xor() */
|
|
|
|
0x21400000, /* FDT[53] - andn() */
|
|
|
|
0x21500000, /* FDT[54] - not() */
|
|
|
|
0x20400000, /* FDT[55] - add() */
|
|
|
|
0x20500000, /* FDT[56] - sub() */
|
|
|
|
0x20800000, /* FDT[57] - lsh() */
|
|
|
|
0x20a00000, /* FDT[58] - rsh() */
|
|
|
|
0xc0170000, /* FDT[59] - crc8() */
|
|
|
|
0xc0145670, /* FDT[60] - crc16() */
|
|
|
|
0xc0345670, /* FDT[61] - crc32() */
|
|
|
|
0xa0076540, /* FDT[62] - endian32() */
|
|
|
|
0xa0000760, /* FDT[63] - endian16() */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-12-22 06:04:10 +08:00
|
|
|
static int bcom_engine_init(void)
|
2007-09-16 18:53:27 +08:00
|
|
|
{
|
|
|
|
int task;
|
|
|
|
phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
|
|
|
|
unsigned int tdt_size, ctx_size, var_size, fdt_size;
|
|
|
|
|
|
|
|
/* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */
|
|
|
|
tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
|
|
|
|
ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE;
|
|
|
|
var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE);
|
|
|
|
fdt_size = BCOM_FDT_SIZE;
|
|
|
|
|
|
|
|
bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa);
|
|
|
|
bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa);
|
|
|
|
bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa);
|
|
|
|
bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa);
|
|
|
|
|
|
|
|
if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) {
|
|
|
|
printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n");
|
|
|
|
|
|
|
|
bcom_sram_free(bcom_eng->tdt);
|
|
|
|
bcom_sram_free(bcom_eng->ctx);
|
|
|
|
bcom_sram_free(bcom_eng->var);
|
|
|
|
bcom_sram_free(bcom_eng->fdt);
|
|
|
|
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(bcom_eng->tdt, 0x00, tdt_size);
|
|
|
|
memset(bcom_eng->ctx, 0x00, ctx_size);
|
|
|
|
memset(bcom_eng->var, 0x00, var_size);
|
|
|
|
memset(bcom_eng->fdt, 0x00, fdt_size);
|
|
|
|
|
|
|
|
/* Copy the FDT for the EU#3 */
|
|
|
|
memcpy(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops));
|
|
|
|
|
|
|
|
/* Initialize Task base structure */
|
|
|
|
for (task=0; task<BCOM_MAX_TASKS; task++)
|
|
|
|
{
|
|
|
|
out_be16(&bcom_eng->regs->tcr[task], 0);
|
|
|
|
out_8(&bcom_eng->regs->ipr[task], 0);
|
|
|
|
|
|
|
|
bcom_eng->tdt[task].context = ctx_pa;
|
|
|
|
bcom_eng->tdt[task].var = var_pa;
|
|
|
|
bcom_eng->tdt[task].fdt = fdt_pa;
|
|
|
|
|
|
|
|
var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE;
|
|
|
|
ctx_pa += BCOM_CTX_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
out_be32(&bcom_eng->regs->taskBar, tdt_pa);
|
|
|
|
|
|
|
|
/* Init 'always' initiator */
|
|
|
|
out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
|
|
|
|
|
2007-10-22 00:52:02 +08:00
|
|
|
/* Disable COMM Bus Prefetch on the original 5200; it's broken */
|
2008-12-21 17:54:28 +08:00
|
|
|
if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)
|
|
|
|
bcom_disable_prefetch();
|
2007-09-16 18:53:27 +08:00
|
|
|
|
|
|
|
/* Init lock */
|
|
|
|
spin_lock_init(&bcom_eng->lock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bcom_engine_cleanup(void)
|
|
|
|
{
|
|
|
|
int task;
|
|
|
|
|
|
|
|
/* Stop all tasks */
|
|
|
|
for (task=0; task<BCOM_MAX_TASKS; task++)
|
|
|
|
{
|
|
|
|
out_be16(&bcom_eng->regs->tcr[task], 0);
|
|
|
|
out_8(&bcom_eng->regs->ipr[task], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
out_be32(&bcom_eng->regs->taskBar, 0ul);
|
|
|
|
|
|
|
|
/* Release the SRAM zones */
|
|
|
|
bcom_sram_free(bcom_eng->tdt);
|
|
|
|
bcom_sram_free(bcom_eng->ctx);
|
|
|
|
bcom_sram_free(bcom_eng->var);
|
|
|
|
bcom_sram_free(bcom_eng->fdt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ======================================================================== */
|
|
|
|
/* OF platform driver */
|
|
|
|
/* ======================================================================== */
|
|
|
|
|
2012-12-22 06:04:10 +08:00
|
|
|
static int mpc52xx_bcom_probe(struct platform_device *op)
|
2007-09-16 18:53:27 +08:00
|
|
|
{
|
|
|
|
struct device_node *ofn_sram;
|
|
|
|
struct resource res_bcom;
|
|
|
|
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
/* Inform user we're ok so far */
|
|
|
|
printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
|
|
|
|
|
|
|
|
/* Get the bestcomm node */
|
2010-04-14 07:12:29 +08:00
|
|
|
of_node_get(op->dev.of_node);
|
2007-09-16 18:53:27 +08:00
|
|
|
|
|
|
|
/* Prepare SRAM */
|
2008-01-25 13:25:31 +08:00
|
|
|
ofn_sram = of_find_matching_node(NULL, mpc52xx_sram_ids);
|
2007-09-16 18:53:27 +08:00
|
|
|
if (!ofn_sram) {
|
|
|
|
printk(KERN_ERR DRIVER_NAME ": "
|
|
|
|
"No SRAM found in device tree\n");
|
|
|
|
rv = -ENODEV;
|
|
|
|
goto error_ofput;
|
|
|
|
}
|
|
|
|
rv = bcom_sram_init(ofn_sram, DRIVER_NAME);
|
|
|
|
of_node_put(ofn_sram);
|
|
|
|
|
|
|
|
if (rv) {
|
|
|
|
printk(KERN_ERR DRIVER_NAME ": "
|
|
|
|
"Error in SRAM init\n");
|
|
|
|
goto error_ofput;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get a clean struct */
|
|
|
|
bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
|
|
|
|
if (!bcom_eng) {
|
|
|
|
rv = -ENOMEM;
|
|
|
|
goto error_sramclean;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save the node */
|
2010-04-14 07:12:29 +08:00
|
|
|
bcom_eng->ofnode = op->dev.of_node;
|
2007-09-16 18:53:27 +08:00
|
|
|
|
|
|
|
/* Get, reserve & map io */
|
2010-04-14 07:12:29 +08:00
|
|
|
if (of_address_to_resource(op->dev.of_node, 0, &res_bcom)) {
|
2007-09-16 18:53:27 +08:00
|
|
|
printk(KERN_ERR DRIVER_NAME ": "
|
|
|
|
"Can't get resource\n");
|
|
|
|
rv = -EINVAL;
|
|
|
|
goto error_sramclean;
|
|
|
|
}
|
|
|
|
|
2013-01-18 09:32:02 +08:00
|
|
|
if (!request_mem_region(res_bcom.start, resource_size(&res_bcom),
|
2007-09-16 18:53:27 +08:00
|
|
|
DRIVER_NAME)) {
|
|
|
|
printk(KERN_ERR DRIVER_NAME ": "
|
|
|
|
"Can't request registers region\n");
|
|
|
|
rv = -EBUSY;
|
|
|
|
goto error_sramclean;
|
|
|
|
}
|
|
|
|
|
|
|
|
bcom_eng->regs_base = res_bcom.start;
|
|
|
|
bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
|
|
|
|
if (!bcom_eng->regs) {
|
|
|
|
printk(KERN_ERR DRIVER_NAME ": "
|
|
|
|
"Can't map registers\n");
|
|
|
|
rv = -ENOMEM;
|
|
|
|
goto error_release;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now, do the real init */
|
|
|
|
rv = bcom_engine_init();
|
|
|
|
if (rv)
|
|
|
|
goto error_unmap;
|
|
|
|
|
|
|
|
/* Done ! */
|
|
|
|
printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
|
2008-07-12 06:17:58 +08:00
|
|
|
(long)bcom_eng->regs_base);
|
2007-09-16 18:53:27 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Error path */
|
|
|
|
error_unmap:
|
|
|
|
iounmap(bcom_eng->regs);
|
|
|
|
error_release:
|
|
|
|
release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
|
|
|
|
error_sramclean:
|
|
|
|
kfree(bcom_eng);
|
|
|
|
bcom_sram_cleanup();
|
|
|
|
error_ofput:
|
2010-04-14 07:12:29 +08:00
|
|
|
of_node_put(op->dev.of_node);
|
2007-09-16 18:53:27 +08:00
|
|
|
|
|
|
|
printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-23 05:52:34 +08:00
|
|
|
static int mpc52xx_bcom_remove(struct platform_device *op)
|
2007-09-16 18:53:27 +08:00
|
|
|
{
|
|
|
|
/* Clean up the engine */
|
|
|
|
bcom_engine_cleanup();
|
|
|
|
|
|
|
|
/* Cleanup SRAM */
|
|
|
|
bcom_sram_cleanup();
|
|
|
|
|
|
|
|
/* Release regs */
|
|
|
|
iounmap(bcom_eng->regs);
|
|
|
|
release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
|
|
|
|
|
|
|
|
/* Release the node */
|
|
|
|
of_node_put(bcom_eng->ofnode);
|
|
|
|
|
|
|
|
/* Release memory */
|
|
|
|
kfree(bcom_eng);
|
|
|
|
bcom_eng = NULL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-17 03:17:14 +08:00
|
|
|
static const struct of_device_id mpc52xx_bcom_of_match[] = {
|
[POWERPC] Fix Oops with TQM5200 on TQM5200
The "bestcomm-core" driver defines its of_match table as follows
static struct of_device_id mpc52xx_bcom_of_match[] = {
{ .type = "dma-controller", .compatible = "fsl,mpc5200-bestcomm", },
{ .type = "dma-controller", .compatible = "mpc5200-bestcomm", },
{},
};
so while registering the driver, the driver's probe function won't be
called, because the device tree node doesn't have a device_type
property. Thus the driver's bcom_engine structure won't be allocated.
Referencing this structure later causes observed Oops.
Checking bcom_eng pointer for NULL before referencing data pointed
by it prevents oopsing, but fec driver still doesn't work (because
of the lost bestcomm match and resulted task allocation failure).
Actually the compatible property exists and should match and so
the fec driver should work.
This removes .type = "dma-controller" from the bestcomm driver's
mpc52xx_bcom_of_match table to solve the problem.
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-03-22 18:49:05 +08:00
|
|
|
{ .compatible = "fsl,mpc5200-bestcomm", },
|
|
|
|
{ .compatible = "mpc5200-bestcomm", },
|
2007-09-16 18:53:27 +08:00
|
|
|
{},
|
|
|
|
};
|
|
|
|
|
|
|
|
MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
|
|
|
|
|
|
|
|
|
2011-02-23 10:59:54 +08:00
|
|
|
static struct platform_driver mpc52xx_bcom_of_platform_driver = {
|
2007-09-16 18:53:27 +08:00
|
|
|
.probe = mpc52xx_bcom_probe,
|
|
|
|
.remove = mpc52xx_bcom_remove,
|
2010-04-14 07:13:02 +08:00
|
|
|
.driver = {
|
|
|
|
.name = DRIVER_NAME,
|
|
|
|
.of_match_table = mpc52xx_bcom_of_match,
|
2007-09-16 18:53:27 +08:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* ======================================================================== */
|
|
|
|
/* Module */
|
|
|
|
/* ======================================================================== */
|
|
|
|
|
|
|
|
static int __init
|
|
|
|
mpc52xx_bcom_init(void)
|
|
|
|
{
|
2011-02-23 10:59:54 +08:00
|
|
|
return platform_driver_register(&mpc52xx_bcom_of_platform_driver);
|
2007-09-16 18:53:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit
|
|
|
|
mpc52xx_bcom_exit(void)
|
|
|
|
{
|
2011-02-23 10:59:54 +08:00
|
|
|
platform_driver_unregister(&mpc52xx_bcom_of_platform_driver);
|
2007-09-16 18:53:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If we're not a module, we must make sure everything is setup before */
|
|
|
|
/* anyone tries to use us ... that's why we use subsys_initcall instead */
|
|
|
|
/* of module_init. */
|
|
|
|
subsys_initcall(mpc52xx_bcom_init);
|
|
|
|
module_exit(mpc52xx_bcom_exit);
|
|
|
|
|
|
|
|
MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
|
|
|
|
MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
|
|
|
|
MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
|
|
|
|
MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
|
|
|