uboot/drivers/misc/qfw_pio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * PIO interface for QFW
   4 *
   5 * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
   6 * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
   7 */
   8
   9#define LOG_CATEGORY UCLASS_QFW
  10
  11#include <asm/io.h>
  12#include <dm/device.h>
  13#include <qfw.h>
  14
  15/*
  16 * PIO ports are correct for x86, which appears to be the only arch that uses
  17 * PIO.
  18 */
  19#define FW_CONTROL_PORT      0x510
  20#define FW_DATA_PORT         0x511
  21#define FW_DMA_PORT_LOW      0x514
  22#define FW_DMA_PORT_HIGH     0x518
  23
  24static void qfw_pio_read_entry_io(struct udevice *dev, u16 entry, u32 size,
  25                                  void *address)
  26{
  27        /*
  28         * writing FW_CFG_INVALID will cause read operation to resume at last
  29         * offset, otherwise read will start at offset 0
  30         *
  31         * Note: on platform where the control register is IO port, the
  32         * endianness is little endian.
  33         */
  34        if (entry != FW_CFG_INVALID)
  35                outw(cpu_to_le16(entry), FW_CONTROL_PORT);
  36
  37        /* the endianness of data register is string-preserving */
  38        u32 i = 0;
  39        u8 *data = address;
  40
  41        while (size--)
  42                data[i++] = inb(FW_DATA_PORT);
  43}
  44
  45/* Read configuration item using fw_cfg DMA interface */
  46static void qfw_pio_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
  47{
  48        /* the DMA address register is big-endian */
  49        outl(cpu_to_be32((uintptr_t)dma), FW_DMA_PORT_HIGH);
  50
  51        while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR);
  52}
  53
  54static int qfw_pio_probe(struct udevice *dev)
  55{
  56        return qfw_register(dev);
  57}
  58
  59static struct dm_qfw_ops qfw_pio_ops = {
  60        .read_entry_io = qfw_pio_read_entry_io,
  61        .read_entry_dma = qfw_pio_read_entry_dma,
  62};
  63
  64U_BOOT_DRIVER(qfw_pio) = {
  65        .name   = "qfw_pio",
  66        .id     = UCLASS_QFW,
  67        .probe  = qfw_pio_probe,
  68        .ops    = &qfw_pio_ops,
  69};
  70