1
0
mirror of https://github.com/DigitalDevices/dddvb.git synced 2023-10-10 13:37:43 +02:00
dddvb/ddbridge/ddbridge-io.c
rjkm bfa8cec850 always use the copy loop with 32bit accesses
64bit access produces errors on some platforms
2021-01-13 14:56:57 +01:00

189 lines
4.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* 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
* along with this program; if not, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#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);
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
ddblwritel0(link, 3, link->regs + 0x10);
gtlw(link);
val = ddblreadl0(link, link->regs + 0x1c);
spin_unlock_irqrestore(&link->lock, flags);
return val;
}
return readl(link->dev->regs + adr);
}
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);
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
ddblwritel0(link, val, link->regs + 0x18);
ddblwritel0(link, 1, link->regs + 0x10);
spin_unlock_irqrestore(&link->lock, flags);
return;
}
writel(val, link->dev->regs + adr);
}
u32 ddbreadl(struct ddb *dev, u32 adr)
{
if (unlikely(adr & 0xf0000000)) {
unsigned long flags;
u32 val, l = (adr >> DDB_LINK_SHIFT) & 3;
struct ddb_link *link = &dev->link[l];
if (!link->regs)
return 0;
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
ddblwritel0(link, 3, link->regs + 0x10);
gtlw(link);
val = ddblreadl0(link, link->regs + 0x1c);
spin_unlock_irqrestore(&link->lock, flags);
return val;
}
return readl(dev->regs + adr);
}
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];
if (!link->regs)
return;
spin_lock_irqsave(&link->lock, flags);
gtlw(link);
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
ddblwritel0(link, val, link->regs + 0x18);
ddblwritel0(link, 1, link->regs + 0x10);
spin_unlock_irqrestore(&link->lock, flags);
return;
}
writel(val, dev->regs + adr);
}
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) {
val = ddbreadl(dev, p & ~3) >> (8 * a);
while ((p & 3) && count) {
*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);
return memcpy_toio(dev->regs + adr, src, count);
}
void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count)
{
return gtlcpyfrom(dev, dst, adr, count);
/* The possible 64 bit read in memcpy_fromio produces errors
on some platforms, i.e. arm64 rpi4
if (unlikely(adr & 0xf0000000))
return gtlcpyfrom(dev, dst, adr, count);
return memcpy_fromio(dst, dev->regs + adr, count);
*/
}