diff options
author | Christian Gromm <christian.gromm@microchip.com> | 2017-01-23 11:40:19 +0100 |
---|---|---|
committer | Christian Gromm <christian.gromm@microchip.com> | 2017-01-23 11:40:19 +0100 |
commit | f19c18408b515c5e33f96893cbe213d9ab30b904 (patch) | |
tree | 59a836c6c4dd36377fce657f4740264d9d7b95fb /driver/hdm-dim2/dim2_hal.c | |
parent | f3ef1a2aa46088c165d1f3b1844f747d395a4799 (diff) |
update driver packagedab_3.99.1dab/3.99.13.99.1
This patch updates the driver package to v1.4.0-stable.
Change-Id: I8cb5f5287c49ea7fc178816d3713099a6e3079a8
Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Diffstat (limited to 'driver/hdm-dim2/dim2_hal.c')
-rw-r--r-- | driver/hdm-dim2/dim2_hal.c | 117 |
1 files changed, 97 insertions, 20 deletions
diff --git a/driver/hdm-dim2/dim2_hal.c b/driver/hdm-dim2/dim2_hal.c index 6f2b6e4..0b9816c 100644 --- a/driver/hdm-dim2/dim2_hal.c +++ b/driver/hdm-dim2/dim2_hal.c @@ -2,7 +2,7 @@ * dim2_hal.c - DIM2 HAL implementation * (MediaLB, Device Interface Macro IP, OS62420) * - * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG + * Copyright (C) 2015-2016, Microchip Technology Germany II GmbH & Co. KG * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -49,6 +49,8 @@ #define DBR_SIZE (16 * 1024) /* specified by IP */ #define DBR_BLOCK_SIZE (DBR_SIZE / 32 / DBR_MAP_SIZE) +#define ROUND_UP_TO(x, d) (((x) + (d) - 1) / (d) * (d)) + /* -------------------------------------------------------------------------- */ /* generic helper functions and macros */ @@ -66,10 +68,19 @@ static inline bool dim_on_error(u8 error_id, const char *error_message) /* -------------------------------------------------------------------------- */ /* types and local variables */ +struct async_tx_dbr { + u8 ch_addr; + u16 rpc; + u16 wpc; + u16 rest_size; + u16 sz_queue[CDT0_RPC_MASK + 1]; +}; + struct lld_global_vars_t { bool dim_is_initialized; bool mcm_is_initialized; struct dim2_regs __iomem *dim2; /* DIM2 core base address */ + struct async_tx_dbr atx_dbr; u32 fcnt; u32 dbr_map[DBR_MAP_SIZE]; }; @@ -251,6 +262,13 @@ static void dim2_configure_cdt(u8 ch_addr, u16 dbr_address, u16 hw_buffer_size, dim2_write_ctr(CDT + ch_addr, cdt); } +static u16 dim2_rpc(u8 ch_addr) +{ + u32 cdt0 = dim2_read_ctr(CDT + ch_addr, 0); + + return (cdt0 >> CDT0_RPC_SHIFT) & CDT0_RPC_MASK; +} + static void dim2_clear_cdt(u8 ch_addr) { u32 cdt[4] = { 0, 0, 0, 0 }; @@ -361,6 +379,49 @@ static void dim2_clear_channel(u8 ch_addr) } /* -------------------------------------------------------------------------- */ +/* trace async tx dbr fill state */ + +static inline u16 norm_pc(u16 pc) +{ + return pc & CDT0_RPC_MASK; +} + +static void dbrcnt_init(u8 ch_addr, u16 dbr_size) +{ + g.atx_dbr.rest_size = dbr_size; + g.atx_dbr.rpc = dim2_rpc(ch_addr); + g.atx_dbr.wpc = g.atx_dbr.rpc; +} + +static void dbrcnt_enq(int buf_sz) +{ + g.atx_dbr.rest_size -= buf_sz; + g.atx_dbr.sz_queue[norm_pc(g.atx_dbr.wpc)] = buf_sz; + g.atx_dbr.wpc++; +} + +u16 dim_dbr_space(struct dim_channel *ch) +{ + u16 cur_rpc; + struct async_tx_dbr *dbr = &g.atx_dbr; + + if (ch->addr != dbr->ch_addr) + return 0xFFFF; + + cur_rpc = dim2_rpc(ch->addr); + + while (norm_pc(dbr->rpc) != cur_rpc) { + dbr->rest_size += dbr->sz_queue[norm_pc(dbr->rpc)]; + dbr->rpc++; + } + + if ((u16)(dbr->wpc - dbr->rpc) >= CDT0_RPC_MASK) + return 0; + + return dbr->rest_size; +} + +/* -------------------------------------------------------------------------- */ /* channel state helpers */ static void state_init(struct int_ch_state *state) @@ -518,20 +579,17 @@ static inline bool service_channel(u8 ch_addr, u8 idx) { u8 const shift = idx * 16; u32 const adt1 = dim2_read_ctr(ADT + ch_addr, 1); + u32 mask[4] = { 0, 0, 0, 0 }; + u32 adt_w[4] = { 0, 0, 0, 0 }; if (((adt1 >> (ADT1_DNE_BIT + shift)) & 1) == 0) return false; - { - u32 mask[4] = { 0, 0, 0, 0 }; - u32 adt_w[4] = { 0, 0, 0, 0 }; - - mask[1] = - bit_mask(ADT1_DNE_BIT + shift) | - bit_mask(ADT1_ERR_BIT + shift) | - bit_mask(ADT1_RDY_BIT + shift); - dim2_write_ctr_mask(ADT + ch_addr, mask, adt_w); - } + mask[1] = + bit_mask(ADT1_DNE_BIT + shift) | + bit_mask(ADT1_ERR_BIT + shift) | + bit_mask(ADT1_RDY_BIT + shift); + dim2_write_ctr_mask(ADT + ch_addr, mask, adt_w); /* clear channel status bit */ dimcb_io_write(&g.dim2->ACSR0, bit_mask(ch_addr)); @@ -615,6 +673,9 @@ static bool channel_start(struct dim_channel *ch, u32 buf_addr, u16 buf_size) ++state->level; + if (ch->addr == g.atx_dbr.ch_addr) + dbrcnt_enq(buf_size); + if (ch->packet_length || ch->bytes_per_frame) dim2_start_isoc_sync(ch->addr, state->idx1, buf_addr, buf_size); else @@ -653,7 +714,8 @@ static bool channel_detach_buffers(struct dim_channel *ch, u16 buffers_number) /* -------------------------------------------------------------------------- */ /* API */ -u8 dim_startup(struct dim2_regs __iomem *dim_base_address, u32 mlb_clock, u32 fcnt) +u8 dim_startup(struct dim2_regs __iomem *dim_base_address, u32 mlb_clock, + u32 fcnt) { g.dim_is_initialized = false; @@ -700,7 +762,7 @@ static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx, if (!check_channel_address(ch_address)) return DIM_INIT_ERR_CHANNEL_ADDRESS; - ch->dbr_size = hw_buffer_size; + ch->dbr_size = ROUND_UP_TO(hw_buffer_size, DBR_BLOCK_SIZE); ch->dbr_addr = alloc_dbr(ch->dbr_size); if (ch->dbr_addr >= DBR_SIZE) return DIM_INIT_ERR_OUT_OF_MEMORY; @@ -713,6 +775,12 @@ static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx, return DIM_NO_ERROR; } +void dim_service_mlb_int_irq(void) +{ + dimcb_io_write(&g.dim2->MS0, 0); + dimcb_io_write(&g.dim2->MS1, 0); +} + u16 dim_norm_ctrl_async_buffer_size(u16 buf_size) { return norm_ctrl_async_buffer_size(buf_size); @@ -756,8 +824,16 @@ u8 dim_init_control(struct dim_channel *ch, u8 is_tx, u16 ch_address, u8 dim_init_async(struct dim_channel *ch, u8 is_tx, u16 ch_address, u16 max_buffer_size) { - return init_ctrl_async(ch, CAT_CT_VAL_ASYNC, is_tx, ch_address, - max_buffer_size); + u8 ret = init_ctrl_async(ch, CAT_CT_VAL_ASYNC, is_tx, ch_address, + max_buffer_size); + + if (is_tx && !g.atx_dbr.ch_addr) { + g.atx_dbr.ch_addr = ch->addr; + dbrcnt_init(ch->addr, ch->dbr_size); + dimcb_io_write(&g.dim2->MIEN, bit_mask(20)); + } + + return ret; } u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address, @@ -818,6 +894,11 @@ u8 dim_destroy_channel(struct dim_channel *ch) if (!g.dim_is_initialized || !ch) return DIM_ERR_DRIVER_NOT_INITIALIZED; + if (ch->addr == g.atx_dbr.ch_addr) { + dimcb_io_write(&g.dim2->MIEN, 0); + g.atx_dbr.ch_addr = 0; + } + dim2_clear_channel(ch->addr); if (ch->dbr_addr < DBR_SIZE) free_dbr(ch->dbr_addr, ch->dbr_size); @@ -826,7 +907,7 @@ u8 dim_destroy_channel(struct dim_channel *ch) return DIM_NO_ERROR; } -void dim_service_irq(struct dim_channel *const *channels) +void dim_service_ahb_int_irq(struct dim_channel *const *channels) { bool state_changed; @@ -858,10 +939,6 @@ void dim_service_irq(struct dim_channel *const *channels) ++ch; } } while (state_changed); - - /* clear pending Interrupts */ - dimcb_io_write(&g.dim2->MS0, 0); - dimcb_io_write(&g.dim2->MS1, 0); } u8 dim_service_channel(struct dim_channel *ch) |