2020-08-29 15:32:42 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2017-08-02 20:22:52 +02:00
|
|
|
/*
|
|
|
|
* ddbridge-io.c: Digital Devices bridge I/O functions
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010-2017 Digital Devices GmbH
|
|
|
|
* Ralph Metzler <rjkm@metzlerbros.de>
|
|
|
|
* Marcus Metzler <mocm@metzlerbros.de>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* version 2 only, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2017-08-26 10:32:53 +02:00
|
|
|
* along with this program; if not, point your browser to
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
2017-08-02 20:22:52 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ddbridge.h"
|
|
|
|
#include "ddbridge-io.h"
|
|
|
|
|
|
|
|
u32 ddblreadl(struct ddb_link *link, u32 adr)
|
|
|
|
{
|
|
|
|
if (unlikely(link->nr)) {
|
|
|
|
unsigned long flags;
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&link->lock, flags);
|
|
|
|
gtlw(link);
|
2017-10-25 23:01:46 +02:00
|
|
|
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
|
|
|
|
ddblwritel0(link, 3, link->regs + 0x10);
|
2017-08-02 20:22:52 +02:00
|
|
|
gtlw(link);
|
2017-10-25 23:01:46 +02:00
|
|
|
val = ddblreadl0(link, link->regs + 0x1c);
|
2017-08-02 20:22:52 +02:00
|
|
|
spin_unlock_irqrestore(&link->lock, flags);
|
|
|
|
return val;
|
|
|
|
}
|
2017-12-11 16:41:32 +01:00
|
|
|
return readl(link->dev->regs + adr);
|
2017-08-02 20:22:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ddblwritel(struct ddb_link *link, u32 val, u32 adr)
|
|
|
|
{
|
|
|
|
if (unlikely(link->nr)) {
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&link->lock, flags);
|
|
|
|
gtlw(link);
|
2017-10-25 23:01:46 +02:00
|
|
|
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
|
|
|
|
ddblwritel0(link, val, link->regs + 0x18);
|
|
|
|
ddblwritel0(link, 1, link->regs + 0x10);
|
2017-08-02 20:22:52 +02:00
|
|
|
spin_unlock_irqrestore(&link->lock, flags);
|
|
|
|
return;
|
|
|
|
}
|
2017-12-11 16:41:32 +01:00
|
|
|
writel(val, link->dev->regs + adr);
|
2017-08-02 20:22:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
u32 ddbreadl(struct ddb *dev, u32 adr)
|
|
|
|
{
|
|
|
|
if (unlikely(adr & 0xf0000000)) {
|
|
|
|
unsigned long flags;
|
2018-05-02 15:45:00 +02:00
|
|
|
u32 val, l = (adr >> DDB_LINK_SHIFT) & 3;
|
2017-08-02 20:22:52 +02:00
|
|
|
struct ddb_link *link = &dev->link[l];
|
|
|
|
|
2020-03-31 16:38:49 +02:00
|
|
|
if (!link->regs)
|
|
|
|
return 0;
|
2017-08-02 20:22:52 +02:00
|
|
|
spin_lock_irqsave(&link->lock, flags);
|
|
|
|
gtlw(link);
|
2017-10-25 23:01:46 +02:00
|
|
|
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
|
|
|
|
ddblwritel0(link, 3, link->regs + 0x10);
|
2017-08-02 20:22:52 +02:00
|
|
|
gtlw(link);
|
2017-10-25 23:01:46 +02:00
|
|
|
val = ddblreadl0(link, link->regs + 0x1c);
|
2017-08-02 20:22:52 +02:00
|
|
|
spin_unlock_irqrestore(&link->lock, flags);
|
|
|
|
return val;
|
|
|
|
}
|
2017-12-11 16:41:32 +01:00
|
|
|
return readl(dev->regs + adr);
|
2017-08-02 20:22:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ddbwritel(struct ddb *dev, u32 val, u32 adr)
|
|
|
|
{
|
|
|
|
if (unlikely(adr & 0xf0000000)) {
|
|
|
|
unsigned long flags;
|
|
|
|
u32 l = (adr >> DDB_LINK_SHIFT);
|
|
|
|
struct ddb_link *link = &dev->link[l];
|
|
|
|
|
2020-03-31 16:38:49 +02:00
|
|
|
if (!link->regs)
|
|
|
|
return;
|
2017-08-02 20:22:52 +02:00
|
|
|
spin_lock_irqsave(&link->lock, flags);
|
|
|
|
gtlw(link);
|
2017-10-25 23:01:46 +02:00
|
|
|
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
|
|
|
|
ddblwritel0(link, val, link->regs + 0x18);
|
|
|
|
ddblwritel0(link, 1, link->regs + 0x10);
|
2017-08-02 20:22:52 +02:00
|
|
|
spin_unlock_irqrestore(&link->lock, flags);
|
|
|
|
return;
|
|
|
|
}
|
2017-12-11 16:41:32 +01:00
|
|
|
writel(val, dev->regs + adr);
|
2017-08-02 20:22:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void gtlcpyto(struct ddb *dev, u32 adr, const u8 *buf,
|
|
|
|
unsigned int count)
|
|
|
|
{
|
|
|
|
u32 val = 0, p = adr;
|
|
|
|
u32 aa = p & 3;
|
|
|
|
|
|
|
|
if (aa) {
|
|
|
|
while (p & 3 && count) {
|
|
|
|
val >>= 8;
|
|
|
|
val |= *buf << 24;
|
|
|
|
p++;
|
|
|
|
buf++;
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
ddbwritel(dev, val, adr);
|
|
|
|
}
|
|
|
|
while (count >= 4) {
|
|
|
|
val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
|
|
|
ddbwritel(dev, val, p);
|
|
|
|
p += 4;
|
|
|
|
buf += 4;
|
|
|
|
count -= 4;
|
|
|
|
}
|
|
|
|
if (count) {
|
|
|
|
val = buf[0];
|
|
|
|
if (count > 1)
|
|
|
|
val |= buf[1] << 8;
|
|
|
|
if (count > 2)
|
|
|
|
val |= buf[2] << 16;
|
|
|
|
ddbwritel(dev, val, p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count)
|
|
|
|
{
|
|
|
|
u32 val = 0, p = adr;
|
|
|
|
u32 a = p & 3;
|
|
|
|
|
|
|
|
if (a) {
|
2021-01-13 14:56:22 +01:00
|
|
|
val = ddbreadl(dev, p & ~3) >> (8 * a);
|
|
|
|
while ((p & 3) && count) {
|
2017-08-02 20:22:52 +02:00
|
|
|
*buf = val & 0xff;
|
|
|
|
val >>= 8;
|
|
|
|
p++;
|
|
|
|
buf++;
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (count >= 4) {
|
|
|
|
val = ddbreadl(dev, p);
|
|
|
|
buf[0] = val & 0xff;
|
|
|
|
buf[1] = (val >> 8) & 0xff;
|
|
|
|
buf[2] = (val >> 16) & 0xff;
|
|
|
|
buf[3] = (val >> 24) & 0xff;
|
|
|
|
p += 4;
|
|
|
|
buf += 4;
|
|
|
|
count -= 4;
|
|
|
|
}
|
|
|
|
if (count) {
|
|
|
|
val = ddbreadl(dev, p);
|
|
|
|
buf[0] = val & 0xff;
|
|
|
|
if (count > 1)
|
|
|
|
buf[1] = (val >> 8) & 0xff;
|
|
|
|
if (count > 2)
|
|
|
|
buf[2] = (val >> 16) & 0xff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count)
|
|
|
|
{
|
|
|
|
if (unlikely(adr & 0xf0000000))
|
|
|
|
return gtlcpyto(dev, adr, src, count);
|
2017-12-11 16:41:32 +01:00
|
|
|
return memcpy_toio(dev->regs + adr, src, count);
|
2017-08-02 20:22:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count)
|
|
|
|
{
|
2021-01-13 14:56:57 +01:00
|
|
|
return gtlcpyfrom(dev, dst, adr, count);
|
|
|
|
/* The possible 64 bit read in memcpy_fromio produces errors
|
|
|
|
on some platforms, i.e. arm64 rpi4
|
2017-08-02 20:22:52 +02:00
|
|
|
if (unlikely(adr & 0xf0000000))
|
|
|
|
return gtlcpyfrom(dev, dst, adr, count);
|
2021-01-13 14:56:57 +01:00
|
|
|
return memcpy_fromio(dst, dev->regs + adr, count);
|
|
|
|
*/
|
|
|
|
|
2017-08-02 20:22:52 +02:00
|
|
|
}
|