Source
x
/*
* Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.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.
*
* 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.
*/
/* System Bus Controller registers */
/* base address of bank0 space */
/* bank_enable */
/* timing parameter 0 of bank0 */
/* timing parameter 1 of bank0 */
/* timing parameter 2 of bank0 */
/* timing parameter 3 of bank0 */
/* timing parameter 4 of bank0 */
/* register stride to next bank */
/* number of banks (chip select) */
/* data to squash bank 0, 1 */
struct uniphier_system_bus_bank {
u32 base;
u32 end;
};
struct uniphier_system_bus_priv {
struct device *dev;
void __iomem *membase;
struct uniphier_system_bus_bank bank[UNIPHIER_SBC_NR_BANKS];
};
static int uniphier_system_bus_add_bank(struct uniphier_system_bus_priv *priv,
int bank, u32 addr, u64 paddr, u32 size)
{
u64 end, mask;
dev_dbg(priv->dev,
"range found: bank = %d, addr = %08x, paddr = %08llx, size = %08x\n",
bank, addr, paddr, size);
if (bank >= ARRAY_SIZE(priv->bank)) {
dev_err(priv->dev, "unsupported bank number %d\n", bank);
return -EINVAL;
}
if (priv->bank[bank].base || priv->bank[bank].end) {
dev_err(priv->dev,
"range for bank %d has already been specified\n", bank);
return -EINVAL;
}
if (paddr > U32_MAX) {
dev_err(priv->dev, "base address %llx is too high\n", paddr);
return -EINVAL;
}
end = paddr + size;
if (addr > paddr) {
dev_err(priv->dev,
"base %08x cannot be mapped to %08llx of parent\n",
addr, paddr);
return -EINVAL;
}
paddr -= addr;
paddr = round_down(paddr, 0x00020000);
end = round_up(end, 0x00020000);
if (end > U32_MAX) {
dev_err(priv->dev, "end address %08llx is too high\n", end);
return -EINVAL;
}
mask = paddr ^ (end - 1);
mask = roundup_pow_of_two(mask);
paddr = round_down(paddr, mask);