// SPDX-License-Identifier: Apache-2.0 // Copyright (C) 2018,2019 IBM Corp. #include "log.h" #include "sio.h" #include #include #include #define SIO_ADDR(ctx) ((ctx)->base) #define SIO_DATA(ctx) ((ctx)->base + 1) int sio_init(struct sio *ctx) { ctx->base = 0x2e; return lpc_init(&ctx->io, "io"); } int sio_destroy(struct sio *ctx) { return lpc_destroy(&ctx->io); } int sio_lock(struct sio *ctx) { return lpc_writeb(&ctx->io, SIO_ADDR(ctx), 0xaa); } int sio_unlock(struct sio *ctx) { int rc; rc = lpc_writeb(&ctx->io, SIO_ADDR(ctx), 0xa5); rc |= lpc_writeb(&ctx->io, SIO_ADDR(ctx), 0xa5); return rc; } int sio_select(struct sio *ctx, enum sio_dev dev) { return sio_writeb(ctx, 0x07, dev); } static int sio_present(struct sio *ctx) { uint8_t dev; int rc; logd("Probing 0x%x for SuperIO\n", ctx->base); /* Dumb heuristics as we don't have access to the LPCHC */ rc = sio_unlock(ctx); logt("Unlocking SuperIO: %d\n", rc); if (rc) goto out; rc = sio_select(ctx, sio_suart1); logt("Selecting SuperIO device %d (SUART1): %d\n", sio_suart1, rc); if (rc) goto out; rc = sio_readb(ctx, 0x07, &dev); logt("Found device %d selected: %d\n", dev, rc); if (rc) goto out; rc = (dev == sio_suart1); if (!rc) goto out; rc = sio_select(ctx, sio_suart4); logt("Selecting SuperIO device %d (SUART4): %d\n", sio_suart4, rc); if (rc) goto out; rc = sio_readb(ctx, 0x07, &dev); logt("Found device %d selected: %d\n", dev, rc); if (rc) goto out; rc = (dev == sio_suart4); out: sio_lock(ctx); logt("Locking SuperIO\n"); return rc; } int sio_probe(struct sio *ctx) { bool found; ctx->base = 0x2e; found = sio_present(ctx); if (!found) { ctx->base = 0x4e; found = sio_present(ctx); } if (found) { logd("Found SuperIO device at 0x%" PRIx16 "\n", ctx->base); } else { logd("SuperIO disabled\n"); } return found; } int sio_readb(struct sio *ctx, uint32_t addr, uint8_t *val) { int rc; rc = lpc_writeb(&ctx->io, SIO_ADDR(ctx), addr); if (rc) return rc; return lpc_readb(&ctx->io, SIO_DATA(ctx), val); } int sio_writeb(struct sio *ctx, uint32_t addr, uint8_t val) { int rc; rc = lpc_writeb(&ctx->io, SIO_ADDR(ctx), addr); if (rc) return rc; return lpc_writeb(&ctx->io, SIO_DATA(ctx), val); }