// SPDX-License-Identifier: Apache-2.0 // Copyright (C) 2018,2019 IBM Corp. #include "ahb.h" #include "log.h" #include "mb.h" #include "mmio.h" #include "p2a.h" #include "pci.h" #include "rev.h" #include #include #include #include #include #include #include #include #define AST_MMIO_BAR 1 #define AST_MMIO_LEN (128 * 1024) #define P2AB_PKR 0xf000 #define P2AB_RBAR 0xf004 #define P2AB_RBAR_REMAP_MASK 0xffff0000 #define P2AB_WINDOW_BASE 0x10000 #define P2AB_WINDOW_LEN 0x10000 static int __p2ab_writel(struct p2ab *ctx, size_t addr, uint32_t val) { assert(addr < (AST_MMIO_LEN - sizeof(val) + 1)); assert(!(addr & (sizeof(val) - 1))); *((uint32_t *)(ctx->mmio + addr)) = htole32(val); iob(); return 0; } static inline int p2ab_unlock(struct p2ab *ctx) { int rc; rc = __p2ab_writel(ctx, P2AB_PKR, 1); return rc; } static inline int p2ab_lock(struct p2ab *ctx) { int rc; rc = __p2ab_writel(ctx, P2AB_PKR, 0); return rc; } int p2ab_init(struct p2ab *ctx, uint16_t vid, uint16_t did) { int rc; rc = pci_open(vid, did, AST_MMIO_BAR); if (rc < 0) return rc; ctx->res = rc; ctx->mmio = mmap(0, AST_MMIO_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, ctx->res, 0); if (ctx->mmio == MAP_FAILED) return -errno; return p2ab_unlock(ctx); } int p2ab_destroy(struct p2ab *ctx) { int rc; rc = p2ab_lock(ctx); if (rc < 0) return rc; rc = munmap(ctx->mmio, AST_MMIO_LEN); if (rc == -1) return -errno; return pci_close(ctx->res); } int p2ab_probe(struct p2ab *ctx) { struct ahb ahb; int64_t rc; logd("Probing %s\n", ahb_interface_names[ahb_p2ab]); rc = rev_probe(ahb_use(&ahb, ahb_p2ab, ctx)); if (rc < 0) return rc; return rc < 0 ? rc : 1; } int64_t p2ab_map(struct p2ab *ctx, uint32_t phys, size_t len) { uint32_t rbar; uint32_t offset; int64_t rc; rbar = phys & P2AB_RBAR_REMAP_MASK; offset = phys & ~P2AB_RBAR_REMAP_MASK; if (ctx->rbar == rbar) return offset; rc = __p2ab_writel(ctx, P2AB_RBAR, rbar); if (rc < 0) return rc; ctx->rbar = rbar; return offset; } ssize_t p2ab_read(struct p2ab *ctx, uint32_t phys, void *buf, size_t len) { size_t remaining = len; size_t ingress; int64_t rc; do { ingress = remaining > P2AB_WINDOW_LEN ? P2AB_WINDOW_LEN : remaining; rc = p2ab_map(ctx, phys, ingress); if (rc < 0) return rc; mmio_memcpy(buf, (ctx->mmio + P2AB_WINDOW_BASE + rc), ingress); phys += ingress; buf += ingress; remaining -= ingress; } while (remaining); return len; } ssize_t p2ab_write(struct p2ab *ctx, uint32_t phys, const void *buf, size_t len) { size_t remaining = len; size_t egress; int64_t rc; do { egress = remaining > P2AB_WINDOW_LEN ? P2AB_WINDOW_LEN : remaining; rc = p2ab_map(ctx, phys, egress); if (rc < 0) return rc; mmio_memcpy((ctx->mmio + P2AB_WINDOW_BASE + rc), buf, egress); phys += egress; buf += egress; remaining -= egress; } while (remaining); return len; } int p2ab_readl(struct p2ab *ctx, uint32_t phys, uint32_t *val) { uint32_t le; ssize_t rc; if (phys & 0x3) return -EINVAL; rc = p2ab_map(ctx, phys, sizeof(*val)); if (rc < 0) return rc; le = *(uint32_t *)(ctx->mmio + P2AB_WINDOW_BASE + rc); *val = le32toh(le); return 0; } int p2ab_writel(struct p2ab *ctx, uint32_t phys, uint32_t val) { int rc; val = htole32(val); rc = p2ab_map(ctx, phys, sizeof(val)); if (rc < 0) return rc; *(uint32_t *)(ctx->mmio + P2AB_WINDOW_BASE + rc) = val; return 0; }