Commit b01483a8 authored by David S. Miller's avatar David S. Miller

Merge branch 'ipa-reg-versions'

Alex Elder says:

====================
net: ipa: update registers for other versions

This series updates IPA and GSI register definitions to permit more
versions of IPA hardware to be supported.  Most of the updates are
informational, updating comments to indicate which IPA versions
support each register and field.  But some registers are new and
others are deprecated.  In a few cases register fields are laid
out differently, and in these cases the changes are a little more
substantive.

I won't claim the result is 100% correct, but it's close, and should
allow all IPA versions 3.x through 4.x to be supported by the driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ae8f5867 2ad6f03b
......@@ -701,7 +701,7 @@ static void gsi_evt_ring_program(struct gsi *gsi, u32 evt_ring_id)
val |= u32_encode_bits(GSI_RING_ELEMENT_SIZE, EV_ELEMENT_SIZE_FMASK);
iowrite32(val, gsi->virt + GSI_EV_CH_E_CNTXT_0_OFFSET(evt_ring_id));
val = u32_encode_bits(size, EV_R_LENGTH_FMASK);
val = ev_r_length_encoded(gsi->version, size);
iowrite32(val, gsi->virt + GSI_EV_CH_E_CNTXT_1_OFFSET(evt_ring_id));
/* The context 2 and 3 registers store the low-order and
......@@ -801,14 +801,14 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell)
channel->tre_ring.index = 0;
/* We program all channels as GPI type/protocol */
val = u32_encode_bits(GSI_CHANNEL_TYPE_GPI, CHTYPE_PROTOCOL_FMASK);
val = chtype_protocol_encoded(gsi->version, GSI_CHANNEL_TYPE_GPI);
if (channel->toward_ipa)
val |= CHTYPE_DIR_FMASK;
val |= u32_encode_bits(channel->evt_ring_id, ERINDEX_FMASK);
val |= u32_encode_bits(GSI_RING_ELEMENT_SIZE, ELEMENT_SIZE_FMASK);
iowrite32(val, gsi->virt + GSI_CH_C_CNTXT_0_OFFSET(channel_id));
val = u32_encode_bits(size, R_LENGTH_FMASK);
val = r_length_encoded(gsi->version, size);
iowrite32(val, gsi->virt + GSI_CH_C_CNTXT_1_OFFSET(channel_id));
/* The context 2 and 3 registers store the low-order and
......@@ -842,6 +842,9 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell)
val |= u32_encode_bits(GSI_ESCAPE_BUF_ONLY,
PREFETCH_MODE_FMASK);
}
/* All channels set DB_IN_BYTES */
if (gsi->version >= IPA_VERSION_4_9)
val |= DB_IN_BYTES;
iowrite32(val, gsi->virt + GSI_CH_C_QOS_OFFSET(channel_id));
......
......@@ -64,6 +64,21 @@
(0x0000c01c + 0x1000 * (ee))
/* All other register offsets are relative to gsi->virt */
/** enum gsi_channel_type - CHTYPE_PROTOCOL field values in CH_C_CNTXT_0 */
enum gsi_channel_type {
GSI_CHANNEL_TYPE_MHI = 0x0,
GSI_CHANNEL_TYPE_XHCI = 0x1,
GSI_CHANNEL_TYPE_GPI = 0x2,
GSI_CHANNEL_TYPE_XDCI = 0x3,
GSI_CHANNEL_TYPE_WDI2 = 0x4,
GSI_CHANNEL_TYPE_GCI = 0x5,
GSI_CHANNEL_TYPE_WDI3 = 0x6,
GSI_CHANNEL_TYPE_MHIP = 0x7,
GSI_CHANNEL_TYPE_AQC = 0x8,
GSI_CHANNEL_TYPE_11AD = 0x9,
};
#define GSI_CH_C_CNTXT_0_OFFSET(ch) \
GSI_EE_N_CH_C_CNTXT_0_OFFSET((ch), GSI_EE_AP)
#define GSI_EE_N_CH_C_CNTXT_0_OFFSET(ch, ee) \
......@@ -78,19 +93,35 @@
#define CHSTATE_FMASK GENMASK(23, 20)
#define ELEMENT_SIZE_FMASK GENMASK(31, 24)
/** enum gsi_channel_type - CHTYPE_PROTOCOL field values in CH_C_CNTXT_0 */
enum gsi_channel_type {
GSI_CHANNEL_TYPE_MHI = 0x0,
GSI_CHANNEL_TYPE_XHCI = 0x1,
GSI_CHANNEL_TYPE_GPI = 0x2,
GSI_CHANNEL_TYPE_XDCI = 0x3,
};
/* Encoded value for CH_C_CNTXT_0 register channel protocol fields */
static inline u32
chtype_protocol_encoded(enum ipa_version version, enum gsi_channel_type type)
{
u32 val;
val = u32_encode_bits(type, CHTYPE_PROTOCOL_FMASK);
if (version < IPA_VERSION_4_5)
return val;
/* Encode upper bit(s) as well */
type >>= hweight32(CHTYPE_PROTOCOL_FMASK);
val |= u32_encode_bits(type, CHTYPE_PROTOCOL_MSB_FMASK);
return val;
}
#define GSI_CH_C_CNTXT_1_OFFSET(ch) \
GSI_EE_N_CH_C_CNTXT_1_OFFSET((ch), GSI_EE_AP)
#define GSI_EE_N_CH_C_CNTXT_1_OFFSET(ch, ee) \
(0x0001c004 + 0x4000 * (ee) + 0x80 * (ch))
#define R_LENGTH_FMASK GENMASK(15, 0)
/* Encoded value for CH_C_CNTXT_1 register R_LENGTH field */
static inline u32 r_length_encoded(enum ipa_version version, u32 length)
{
if (version < IPA_VERSION_4_9)
return u32_encode_bits(length, GENMASK(15, 0));
return u32_encode_bits(length, GENMASK(19, 0));
}
#define GSI_CH_C_CNTXT_2_OFFSET(ch) \
GSI_EE_N_CH_C_CNTXT_2_OFFSET((ch), GSI_EE_AP)
......@@ -114,6 +145,9 @@ enum gsi_channel_type {
/* The next two fields are present for IPA v4.5 and above */
#define PREFETCH_MODE_FMASK GENMASK(13, 10)
#define EMPTY_LVL_THRSHOLD_FMASK GENMASK(23, 16)
/* The next field is present for IPA v4.9 and above */
#define DB_IN_BYTES GENMASK(24, 24)
/** enum gsi_prefetch_mode - PREFETCH_MODE field in CH_C_QOS */
enum gsi_prefetch_mode {
GSI_USE_PREFETCH_BUFS = 0x0,
......@@ -146,19 +180,25 @@ enum gsi_prefetch_mode {
GSI_EE_N_EV_CH_E_CNTXT_0_OFFSET((ev), GSI_EE_AP)
#define GSI_EE_N_EV_CH_E_CNTXT_0_OFFSET(ev, ee) \
(0x0001d000 + 0x4000 * (ee) + 0x80 * (ev))
/* enum gsi_channel_type defines EV_CHTYPE field values in EV_CH_E_CNTXT_0 */
#define EV_CHTYPE_FMASK GENMASK(3, 0)
#define EV_EE_FMASK GENMASK(7, 4)
#define EV_EVCHID_FMASK GENMASK(15, 8)
#define EV_INTYPE_FMASK GENMASK(16, 16)
#define EV_CHSTATE_FMASK GENMASK(23, 20)
#define EV_ELEMENT_SIZE_FMASK GENMASK(31, 24)
/* enum gsi_channel_type defines EV_CHTYPE field values in EV_CH_E_CNTXT_0 */
#define GSI_EV_CH_E_CNTXT_1_OFFSET(ev) \
GSI_EE_N_EV_CH_E_CNTXT_1_OFFSET((ev), GSI_EE_AP)
#define GSI_EE_N_EV_CH_E_CNTXT_1_OFFSET(ev, ee) \
(0x0001d004 + 0x4000 * (ee) + 0x80 * (ev))
#define EV_R_LENGTH_FMASK GENMASK(15, 0)
/* Encoded value for EV_CH_C_CNTXT_1 register EV_R_LENGTH field */
static inline u32 ev_r_length_encoded(enum ipa_version version, u32 length)
{
if (version < IPA_VERSION_4_9)
return u32_encode_bits(length, GENMASK(15, 0));
return u32_encode_bits(length, GENMASK(19, 0));
}
#define GSI_EV_CH_E_CNTXT_2_OFFSET(ev) \
GSI_EE_N_EV_CH_E_CNTXT_2_OFFSET((ev), GSI_EE_AP)
......@@ -248,6 +288,7 @@ enum gsi_ch_cmd_opcode {
GSI_CH_STOP = 0x2,
GSI_CH_RESET = 0x9,
GSI_CH_DE_ALLOC = 0xa,
GSI_CH_DB_STOP = 0xb,
};
#define GSI_EV_CH_CMD_OFFSET \
......@@ -278,6 +319,7 @@ enum gsi_generic_cmd_opcode {
GSI_GENERIC_ALLOCATE_CHANNEL = 0x2,
};
/* The next register is present for IPA v3.5.1 and above */
#define GSI_GSI_HW_PARAM_2_OFFSET \
GSI_EE_N_GSI_HW_PARAM_2_OFFSET(GSI_EE_AP)
#define GSI_EE_N_GSI_HW_PARAM_2_OFFSET(ee) \
......@@ -300,7 +342,7 @@ enum gsi_generic_cmd_opcode {
enum gsi_iram_size {
IRAM_SIZE_ONE_KB = 0x0,
IRAM_SIZE_TWO_KB = 0x1,
/* The next two values are available for IPA v4.0 and above */
/* The next two values are available for IPA v4.0 and above */
IRAM_SIZE_TWO_N_HALF_KB = 0x2,
IRAM_SIZE_THREE_KB = 0x3,
/* The next two values are available for IPA v4.5 and above */
......@@ -424,6 +466,8 @@ enum gsi_general_id {
GSI_EE_N_ERROR_LOG_OFFSET(GSI_EE_AP)
#define GSI_EE_N_ERROR_LOG_OFFSET(ee) \
(0x0001f200 + 0x4000 * (ee))
/* Fields below are present for IPA v3.5.1 and above */
#define ERR_ARG3_FMASK GENMASK(3, 0)
#define ERR_ARG2_FMASK GENMASK(7, 4)
#define ERR_ARG1_FMASK GENMASK(11, 8)
......@@ -474,7 +518,4 @@ enum gsi_generic_ee_result {
GENERIC_EE_NO_RESOURCES = 0x7,
};
#define USB_MAX_PACKET_FMASK GENMASK(15, 15) /* 0: HS; 1: SS */
#define MHI_BASE_CHANNEL_FMASK GENMASK(31, 24)
#endif /* _GSI_REG_H_ */
......@@ -54,12 +54,14 @@ static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id)
bool uc_irq = ipa_interrupt_uc(interrupt, irq_id);
struct ipa *ipa = interrupt->ipa;
u32 mask = BIT(irq_id);
u32 offset;
/* For microcontroller interrupts, clear the interrupt right away,
* "to avoid clearing unhandled interrupts."
*/
offset = ipa_reg_irq_clr_offset(ipa->version);
if (uc_irq)
iowrite32(mask, ipa->reg_virt + IPA_REG_IRQ_CLR_OFFSET);
iowrite32(mask, ipa->reg_virt + offset);
if (irq_id < IPA_IRQ_COUNT && interrupt->handler[irq_id])
interrupt->handler[irq_id](interrupt->ipa, irq_id);
......@@ -69,7 +71,7 @@ static void ipa_interrupt_process(struct ipa_interrupt *interrupt, u32 irq_id)
* so defer clearing until after the handler has been called.
*/
if (!uc_irq)
iowrite32(mask, ipa->reg_virt + IPA_REG_IRQ_CLR_OFFSET);
iowrite32(mask, ipa->reg_virt + offset);
}
/* Process all IPA interrupt types that have been signaled */
......@@ -77,13 +79,15 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt)
{
struct ipa *ipa = interrupt->ipa;
u32 enabled = interrupt->enabled;
u32 offset;
u32 mask;
/* The status register indicates which conditions are present,
* including conditions whose interrupt is not enabled. Handle
* only the enabled ones.
*/
mask = ioread32(ipa->reg_virt + IPA_REG_IRQ_STTS_OFFSET);
offset = ipa_reg_irq_stts_offset(ipa->version);
mask = ioread32(ipa->reg_virt + offset);
while ((mask &= enabled)) {
do {
u32 irq_id = __ffs(mask);
......@@ -92,7 +96,7 @@ static void ipa_interrupt_process_all(struct ipa_interrupt *interrupt)
ipa_interrupt_process(interrupt, irq_id);
} while (mask);
mask = ioread32(ipa->reg_virt + IPA_REG_IRQ_STTS_OFFSET);
mask = ioread32(ipa->reg_virt + offset);
}
}
......@@ -115,14 +119,17 @@ static irqreturn_t ipa_isr(int irq, void *dev_id)
{
struct ipa_interrupt *interrupt = dev_id;
struct ipa *ipa = interrupt->ipa;
u32 offset;
u32 mask;
mask = ioread32(ipa->reg_virt + IPA_REG_IRQ_STTS_OFFSET);
offset = ipa_reg_irq_stts_offset(ipa->version);
mask = ioread32(ipa->reg_virt + offset);
if (mask & interrupt->enabled)
return IRQ_WAKE_THREAD;
/* Nothing in the mask was supposed to cause an interrupt */
iowrite32(mask, ipa->reg_virt + IPA_REG_IRQ_CLR_OFFSET);
offset = ipa_reg_irq_clr_offset(ipa->version);
iowrite32(mask, ipa->reg_virt + offset);
dev_err(&ipa->pdev->dev, "%s: unexpected interrupt, mask 0x%08x\n",
__func__, mask);
......@@ -136,15 +143,22 @@ static void ipa_interrupt_suspend_control(struct ipa_interrupt *interrupt,
{
struct ipa *ipa = interrupt->ipa;
u32 mask = BIT(endpoint_id);
u32 offset;
u32 val;
/* assert(mask & ipa->available); */
val = ioread32(ipa->reg_virt + IPA_REG_IRQ_SUSPEND_EN_OFFSET);
/* IPA version 3.0 does not support TX_SUSPEND interrupt control */
if (ipa->version == IPA_VERSION_3_0)
return;
offset = ipa_reg_irq_suspend_en_offset(ipa->version);
val = ioread32(ipa->reg_virt + offset);
if (enable)
val |= mask;
else
val &= ~mask;
iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_SUSPEND_EN_OFFSET);
iowrite32(val, ipa->reg_virt + offset);
}
/* Enable TX_SUSPEND for an endpoint */
......@@ -165,10 +179,18 @@ ipa_interrupt_suspend_disable(struct ipa_interrupt *interrupt, u32 endpoint_id)
void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt)
{
struct ipa *ipa = interrupt->ipa;
u32 offset;
u32 val;
val = ioread32(ipa->reg_virt + IPA_REG_IRQ_SUSPEND_INFO_OFFSET);
iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_SUSPEND_CLR_OFFSET);
offset = ipa_reg_irq_suspend_info_offset(ipa->version);
val = ioread32(ipa->reg_virt + offset);
/* SUSPEND interrupt status isn't cleared on IPA version 3.0 */
if (ipa->version == IPA_VERSION_3_0)
return;
offset = ipa_reg_irq_suspend_clr_offset(ipa->version);
iowrite32(val, ipa->reg_virt + offset);
}
/* Simulate arrival of an IPA TX_SUSPEND interrupt */
......@@ -182,13 +204,15 @@ void ipa_interrupt_add(struct ipa_interrupt *interrupt,
enum ipa_irq_id ipa_irq, ipa_irq_handler_t handler)
{
struct ipa *ipa = interrupt->ipa;
u32 offset;
/* assert(ipa_irq < IPA_IRQ_COUNT); */
interrupt->handler[ipa_irq] = handler;
/* Update the IPA interrupt mask to enable it */
interrupt->enabled |= BIT(ipa_irq);
iowrite32(interrupt->enabled, ipa->reg_virt + IPA_REG_IRQ_EN_OFFSET);
offset = ipa_reg_irq_en_offset(ipa->version);
iowrite32(interrupt->enabled, ipa->reg_virt + offset);
}
/* Remove the handler for an IPA interrupt type */
......@@ -196,11 +220,13 @@ void
ipa_interrupt_remove(struct ipa_interrupt *interrupt, enum ipa_irq_id ipa_irq)
{
struct ipa *ipa = interrupt->ipa;
u32 offset;
/* assert(ipa_irq < IPA_IRQ_COUNT); */
/* Update the IPA interrupt mask to disable it */
interrupt->enabled &= ~BIT(ipa_irq);
iowrite32(interrupt->enabled, ipa->reg_virt + IPA_REG_IRQ_EN_OFFSET);
offset = ipa_reg_irq_en_offset(ipa->version);
iowrite32(interrupt->enabled, ipa->reg_virt + offset);
interrupt->handler[ipa_irq] = NULL;
}
......@@ -211,6 +237,7 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
struct device *dev = &ipa->pdev->dev;
struct ipa_interrupt *interrupt;
unsigned int irq;
u32 offset;
int ret;
ret = platform_get_irq_byname(ipa->pdev, "ipa");
......@@ -228,7 +255,8 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa)
interrupt->irq = irq;
/* Start with all IPA interrupts disabled */
iowrite32(0, ipa->reg_virt + IPA_REG_IRQ_EN_OFFSET);
offset = ipa_reg_irq_en_offset(ipa->version);
iowrite32(0, ipa->reg_virt + offset);
ret = request_threaded_irq(irq, ipa_isr, ipa_isr_thread, IRQF_ONESHOT,
"ipa", interrupt);
......
......@@ -222,7 +222,7 @@ static void ipa_teardown(struct ipa *ipa)
gsi_teardown(&ipa->gsi);
}
/* Configure QMB Core Master Port selection */
/* Configure bus access behavior for IPA components */
static void ipa_hardware_config_comp(struct ipa *ipa)
{
u32 val;
......
This diff is collapsed.
......@@ -192,6 +192,7 @@ void ipa_uc_teardown(struct ipa *ipa)
static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param)
{
struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa);
u32 offset;
u32 val;
/* Fill in the command data */
......@@ -203,8 +204,8 @@ static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param)
/* Use an interrupt to tell the microcontroller the command is ready */
val = u32_encode_bits(1, UC_INTR_FMASK);
iowrite32(val, ipa->reg_virt + IPA_REG_IRQ_UC_OFFSET);
offset = ipa_reg_irq_uc_offset(ipa->version);
iowrite32(val, ipa->reg_virt + offset);
}
/* Tell the microcontroller the AP is shutting down */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment