231 lines
8.3 KiB
C
231 lines
8.3 KiB
C
/*-
|
|
* Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
|
|
* All rights reserved.
|
|
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD: releng/12.2/sys/dev/sdhci/sdhci.h 346394 2019-04-19 15:50:51Z bz $
|
|
*/
|
|
|
|
#ifndef DEV_MMC_HCI_H
|
|
#define DEV_MMC_HCI_H
|
|
|
|
#include "mmc_subr_bus.h"
|
|
#include "mmcreg.h"
|
|
|
|
#define HCI_CAPABILITIES 0x40
|
|
#define HCI_TIMEOUT_CLK_MASK 0x0000003F
|
|
#define HCI_TIMEOUT_CLK_SHIFT 0
|
|
#define HCI_TIMEOUT_CLK_UNIT 0x00000080
|
|
#define HCI_CLOCK_BASE_MASK 0x00003F00
|
|
#define HCI_CLOCK_V3_BASE_MASK 0x0000FF00
|
|
#define HCI_CLOCK_BASE_SHIFT 8
|
|
#define HCI_MAX_BLOCK_MASK 0x00030000
|
|
#define HCI_MAX_BLOCK_SHIFT 16
|
|
#define HCI_CAN_DO_8BITBUS 0x00040000
|
|
#define HCI_CAN_DO_ADMA2 0x00080000
|
|
#define HCI_CAN_DO_HISPD 0x00200000
|
|
#define HCI_CAN_DO_SDMA 0x00400000
|
|
#define HCI_CAN_DO_SUSPEND 0x00800000
|
|
#define HCI_CAN_VDD_330 0x01000000
|
|
#define HCI_CAN_VDD_300 0x02000000
|
|
#define HCI_CAN_VDD_180 0x04000000
|
|
|
|
#define HCI_CAN_DO_ADMA2_64BIT 0x10000000
|
|
#define HCI_CAN_ASYNC_INTR 0x20000000
|
|
#define HCI_SLOTTYPE_MASK 0xC0000000
|
|
|
|
#define HCI_SLOTTYPE_REMOVABLE 0x00000000 /* used for SD slot */
|
|
#define HCI_SLOTTYPE_EMBEDDED 0x40000000 /* used for EMMC slot */
|
|
#define HCI_SLOTTYPE_SDIO 0x80000000
|
|
|
|
#define HCI_CAPABILITIES2 0x44
|
|
#define HCI_CAN_SDR50 0x00000001
|
|
#define HCI_CAN_SDR104 0x00000002
|
|
#define HCI_CAN_HS200 HCI_CAN_SDR104
|
|
#define HCI_CAN_DDR50 0x00000004
|
|
#define HCI_CAN_DRIVE_TYPE_A 0x00000010
|
|
#define HCI_CAN_DRIVE_TYPE_C 0x00000020
|
|
#define HCI_CAN_DRIVE_TYPE_D 0x00000040
|
|
#define HCI_RETUNE_CNT_MASK 0x00000F00
|
|
#define HCI_RETUNE_CNT_SHIFT 8
|
|
#define HCI_TUNE_SDR50 0x00002000
|
|
#define HCI_RETUNE_MODES_MASK 0x0000C000
|
|
#define HCI_RETUNE_MODES_SHIFT 14
|
|
#define HCI_CLOCK_MULT_MASK 0x00FF0000
|
|
#define HCI_CLOCK_MULT_SHIFT 16
|
|
#define MCI_CAN_DO_IDMAC 0x01000000 /* non-standard */
|
|
#define MCI_CAN_DO_IDMAC_64BIT 0x02000000 /* non-standard */
|
|
#define HCI_CAN_MMC_HS400 0x80000000 /* non-standard */
|
|
#define HCI_CAN_MMC_HS400ES 0x40000000 /* non-standard */
|
|
|
|
#define HCI_QUIRK_POLL_CARD_PRESENT (1 << 17)
|
|
|
|
/*
|
|
* Hci: host controller interface
|
|
* capacities of host controller
|
|
* that all host will have
|
|
*/
|
|
typedef struct {
|
|
uint32_t caps;
|
|
uint32_t caps2;
|
|
uint32_t min_clk;
|
|
uint32_t max_clk;
|
|
uint32_t quirks;
|
|
} hci_caps;
|
|
|
|
typedef void (*sdio_irq_cb)(void *arg);
|
|
|
|
/*
|
|
* hci: host controller interface
|
|
*/
|
|
struct hci_softc {
|
|
uint32_t num;
|
|
device_t dev;
|
|
void *peri_base;
|
|
dpal_resource_t *irq_res;
|
|
void *slot;
|
|
uint32_t mmchs_clk_id;
|
|
uint32_t peri_crg_reg;
|
|
uint32_t base;
|
|
uint32_t baseclk_hz;
|
|
uint32_t cmd_and_mode;
|
|
uint32_t sdhci_clkdiv;
|
|
bool disable_highspeed;
|
|
bool force_card_present;
|
|
hci_caps caps; /* The low-level interface between platform and the drivers. */
|
|
uint32_t tuning_phase;
|
|
#define HCI_EVENT_PLUGGED (1U << 0)
|
|
#define HCI_EVENT_UNPLUGGED (1U << 1)
|
|
|
|
/* Note: the mask does not include POST, it's done-event. */
|
|
#define HCI_EVENT_MASK (HCI_EVENT_PLUGGED | HCI_EVENT_UNPLUGGED)
|
|
/*
|
|
* Power control of cd-sw,
|
|
* when set, the host would not set the power again,
|
|
* that will result in miss-behave of power on/off
|
|
*/
|
|
uint32_t no_power;
|
|
sdio_irq_cb sdio_cb;
|
|
void *sdio_arg;
|
|
bool sdio_rescan_allow;
|
|
};
|
|
|
|
/*
|
|
* hci: host controller interface
|
|
*/
|
|
typedef struct {
|
|
int (*read_ivar)(device_t bus, device_t child, int which, uintptr_t *result);
|
|
int (*write_ivar)(device_t bus, device_t child, int which, uintptr_t value);
|
|
void (*update_ios)(device_t brdev, device_t reqdev);
|
|
int (*request)(device_t brdev, device_t reqdev, struct mmc_request *req);
|
|
void (*handle_error)(device_t reqdev, const struct mmc_request *req);
|
|
int (*tune)(device_t brdev, device_t reqdev);
|
|
int (*switch_vccq)(device_t brdev, device_t reqdev);
|
|
u_int (*get_card_busy)(device_t brdev, device_t reqdev);
|
|
int (*retune)(device_t brdev, device_t reqdev, bool reset);
|
|
int (*get_ro)(device_t brdev, device_t reqdev);
|
|
int (*acquire_host)(device_t brdev, device_t reqdev);
|
|
int (*release_host)(device_t brdev, device_t reqdev);
|
|
uint8_t (*readb)(device_t dev, uint32_t off);
|
|
uint16_t (*readw)(device_t dev, uint32_t off);
|
|
uint32_t (*readl)(device_t dev, uint32_t off);
|
|
void (*writeb)(device_t dev, uint32_t off, uint8_t val);
|
|
void (*writew)(device_t dev, uint32_t off, uint16_t val);
|
|
void (*writel)(device_t dev, uint32_t off, uint32_t val);
|
|
bool (*get_card_present)(device_t brdev);
|
|
void (*set_card_present)(device_t brdev, uint32_t p);
|
|
bool (*proc_get_card_present)(device_t brdev);
|
|
bool (*proc_get_card_attach)(device_t brdev);
|
|
void (*set_uhs_timing)(device_t brdev);
|
|
void (*enable_sdio_irq)(device_t brdev);
|
|
int (*registor_sdio_irq)(device_t brdev, sdio_irq_cb cb, void *arg);
|
|
uint32_t (*get_host_id)(device_t reqdev);
|
|
bool (*set_ext_clk_switch)(device_t bus, bool en);
|
|
} hci_ops;
|
|
|
|
/*
|
|
* The HISI platform, HI3516EV200,HI3516EV300,HI3518EV300 are using
|
|
* the same host controller which are very alike.
|
|
* Register the board special methods which are different between the above boards
|
|
* that host can normally use it.
|
|
*/
|
|
typedef struct {
|
|
uint32_t (*set_clock)(struct hci_softc *sc, uint32_t clock);
|
|
void (*extra_init)(struct hci_softc *sc);
|
|
void (*slot_init)(struct hci_softc *sc);
|
|
void (*pre_clock)(struct hci_softc *sc);
|
|
void (*post_clock)(struct hci_softc *sc);
|
|
void (*set_phase)(struct hci_softc *sc, uint32_t timing);
|
|
void (*enable_drv_sample)(struct hci_softc *sc, uint32_t en);
|
|
void (*select_sample_phase)(struct hci_softc *sc, uint32_t phase);
|
|
int (*switch_volt)(struct hci_softc *sc, uint32_t vccq);
|
|
void (*soft_reset)(struct hci_softc *sc);
|
|
uint32_t (*get_taps)(struct hci_softc *sc);
|
|
void (*set_drv)(struct hci_softc *sc, uint32_t timing, uint32_t clk);
|
|
void (*dump_regs)(struct hci_softc *sc);
|
|
void (*drv_ext_clk_switch)(struct hci_softc *sc, bool en);
|
|
} hci_slot_ops;
|
|
|
|
/*
|
|
* This interface would be used when device is not in bus
|
|
* cannot use READ_IVAR because it has 2 parameters, bus and device.
|
|
* that the slot_* interface may not have device in slot.
|
|
*/
|
|
static __inline void slot_set_card_present(device_t bus, uint32_t p)
|
|
{
|
|
hci_ops *ops = (hci_ops *)get_mmcbus_ops(bus);
|
|
ops->set_card_present(bus, p);
|
|
}
|
|
|
|
static __inline bool slot_get_card_present(device_t bus)
|
|
{
|
|
hci_ops *ops = (hci_ops *)get_mmcbus_ops(bus);
|
|
return (ops->get_card_present(bus));
|
|
}
|
|
|
|
static __inline bool slot_proc_get_card_present(device_t bus)
|
|
{
|
|
hci_ops *ops = (hci_ops *)get_mmcbus_ops(bus);
|
|
return (ops->proc_get_card_present(bus));
|
|
}
|
|
|
|
static __inline bool slot_proc_get_card_attach(device_t bus)
|
|
{
|
|
hci_ops *ops = (hci_ops *)get_mmcbus_ops(bus);
|
|
return (ops->proc_get_card_attach(bus));
|
|
}
|
|
|
|
static __inline bool slot_set_ext_clk_switch(device_t bus, bool en)
|
|
{
|
|
hci_ops *ops = (hci_ops *)get_mmcbus_ops(bus);
|
|
return (ops->set_ext_clk_switch(bus, en));
|
|
}
|
|
|
|
void init_slot_methods(int slot, hci_slot_ops *slot_ops);
|
|
void hci_dma_clean_cache(void *addr, uint32_t size);
|
|
void hci_dma_inv_cache(void *addr, uint32_t size);
|
|
int hci_registor_sdio_irq(device_t brdev, sdio_irq_cb cb, void *arg);
|
|
struct hci_softc *get_mmc_resource(int index);
|
|
int set_mmc_resource(struct hci_softc *sc, int index);
|
|
#endif /* DEV_MMC_HCI_H */
|