/* * Copyright (C) 2023 Texas Instruments Incorporated * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "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 COPYRIGHT * OWNER OR CONTRIBUTORS 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. */ #include #include #include #include #include #include #include #include "endat_periodic_trigger.h" #include #include #include HwiP_Params hwiPrms; static HwiP_Object gIcssgEncoderHwiObject0; /* ICSSG EnDat PRU FW HWI */ static HwiP_Object gIcssgEncoderHwiObject1; /* ICSSG EnDat PRU FW HWI */ static HwiP_Object gIcssgEncoderHwiObject2; /* ICSSG EnDat PRU FW HWI */ /* ICSSG Interrupt settings */ #define ICSSG_PRU_ENDAT_INT_NUM ( CSLR_R5FSS0_CORE0_INTR_PRU_ICSSG0_PR1_HOST_INTR_PEND_0 ) uint32_t gPruEnDatIrqCnt0; uint32_t gPruEnDatIrqCnt1; uint32_t gPruEnDatIrqCnt2; /*global variable */ void *gPruss_iep; PRUICSS_Handle gPruIcssXHandle; /* ICSS INTC configuration */ static const PRUICSS_IntcInitData gPruicssIntcInitdata = PRUICSS_INTC_INITDATA; void endat_config_iep(struct endat_periodic_interface *endat_periodic_interface) { /*reset iep timer*/ void *pruss_iep = endat_periodic_interface->pruss_iep; struct endat_pruss_xchg *pruss_xchg = endat_periodic_interface->pruss_dmem; uint8_t temp; uint8_t event; uint32_t cmp_reg0; uint32_t cmp_reg1; uint32_t event_clear; uint64_t cmp0 = 0; /*clear IEP*/ temp = HW_RD_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_GLOBAL_CFG_REG ); temp &= 0xFE; HW_WR_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_GLOBAL_CFG_REG, temp); /* cmp cfg reg */ event = HW_RD_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP_CFG_REG); event_clear = HW_RD_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP_STATUS_REG); /*enable IEP reset by cmp0 event*/ event |= IEP_CMP0_ENABLE; event |= IEP_RST_CNT_EN; event_clear |= 1; /*set IEP counter to ZERO*/ HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_COUNT_REG0, 0); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_COUNT_REG1, 0); /*Clear all event & configure*/ if(endat_periodic_interface->load_share) { event |= pruss_xchg->config[0].channel==1?(0x1 << 4 ):0; //CMP3 for ch0 event |= pruss_xchg->config[1].channel==2?(0x1 << 6 ):0; //CMP5 for Ch1 event |= pruss_xchg->config[2].channel==4?(0x1 << 7 ):0; //CMP6 for CH2 /*clear event*/ event_clear |= pruss_xchg->config[0].channel==1?(0x1 << 3 ):0; //CMP3 for ch0 event_clear |= pruss_xchg->config[1].channel==2?(0x1 << 5 ):0; //CMP5 for Ch1 event_clear |= pruss_xchg->config[2].channel==4?(0x1 << 6 ):0; //CMP6 for CH2 if(pruss_xchg->config[0].channel) { cmp_reg0 = (endat_periodic_interface->cmp3 & 0xffffffff) - IEP_DEFAULT_INC; cmp_reg1 = (endat_periodic_interface->cmp3>>32 & 0xffffffff); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP3_REG0, cmp_reg0); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP3_REG1, cmp_reg1); cmp0 = cmp0 > endat_periodic_interface->cmp3 ? cmp0: endat_periodic_interface->cmp3; } if(pruss_xchg->config[1].channel) { cmp_reg0 = (endat_periodic_interface->cmp5 & 0xffffffff) - IEP_DEFAULT_INC; cmp_reg1 = (endat_periodic_interface->cmp5>>32 & 0xffffffff); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP5_REG0, cmp_reg0); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP5_REG1, cmp_reg1); cmp0 = cmp0 > endat_periodic_interface->cmp5 ? cmp0: endat_periodic_interface->cmp5; } if(pruss_xchg->config[2].channel) { cmp_reg0 = (endat_periodic_interface->cmp6 & 0xffffffff) - IEP_DEFAULT_INC; cmp_reg1 = (endat_periodic_interface->cmp6>>32 & 0xffffffff); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP6_REG0, cmp_reg0); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP6_REG1, cmp_reg1); cmp0 = cmp0 > endat_periodic_interface->cmp6 ? cmp0: endat_periodic_interface->cmp6; } } else { event |= (0x1 << 4 ); event_clear |= (0x1 << 3); cmp_reg0 = (endat_periodic_interface->cmp3 & 0xffffffff) - IEP_DEFAULT_INC; cmp_reg1 = (endat_periodic_interface->cmp3>>32 & 0xffffffff); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP3_REG0, cmp_reg0); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP3_REG1, cmp_reg1); cmp0 = endat_periodic_interface->cmp3; } /*clear event*/ HW_WR_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP_STATUS_REG, event_clear); /*enable event*/ HW_WR_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP_CFG_REG, event); /*configure cmp0 registers*/ cmp0 = 2*cmp0; cmp_reg0 = (cmp0 & 0xffffffff) - IEP_DEFAULT_INC; cmp_reg1 = (cmp0>>32 & 0xffffffff); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP0_REG0, cmp_reg0); HW_WR_REG32((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_CMP0_REG1, cmp_reg1); /*write IEP default increment & IEP start*/ temp = HW_RD_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_GLOBAL_CFG_REG ); temp &= 0x0F; temp |= 0x10; temp |= IEP_COUNTER_EN; HW_WR_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_GLOBAL_CFG_REG, temp); } void endat_interrupt_config(struct endat_periodic_interface *endat_periodic_interface) { struct endat_pruss_xchg *pruss_xchg = endat_periodic_interface->pruss_dmem; int32_t status; if(endat_periodic_interface->load_share) { if(pruss_xchg->config[0].channel) { /* Register & enable ICSSG EnDat PRU FW interrupt */ HwiP_Params_init(&hwiPrms); hwiPrms.intNum = ICSSG_PRU_ENDAT_INT_NUM; hwiPrms.callback = &pruEnDatIrqHandler0; hwiPrms.args = 0; hwiPrms.isPulse = FALSE; hwiPrms.isFIQ = FALSE; status = HwiP_construct(&gIcssgEncoderHwiObject0, &hwiPrms); DebugP_assert(status == SystemP_SUCCESS); } if(pruss_xchg->config[1].channel) { /* Register & enable ICSSG EnDat PRU FW interrupt */ HwiP_Params_init(&hwiPrms); hwiPrms.intNum = ICSSG_PRU_ENDAT_INT_NUM + 1; hwiPrms.callback = &pruEnDatIrqHandler1; hwiPrms.args = 0; hwiPrms.isPulse = FALSE; hwiPrms.isFIQ = FALSE; status = HwiP_construct(&gIcssgEncoderHwiObject1, &hwiPrms); DebugP_assert(status == SystemP_SUCCESS); } if(pruss_xchg->config[2].channel) { /* Register & enable ICSSG EnDat PRU FW interrupt */ HwiP_Params_init(&hwiPrms); hwiPrms.intNum = ICSSG_PRU_ENDAT_INT_NUM + 2; hwiPrms.callback = &pruEnDatIrqHandler2; hwiPrms.args = 0; hwiPrms.isPulse = FALSE; hwiPrms.isFIQ = FALSE; status = HwiP_construct(&gIcssgEncoderHwiObject2, &hwiPrms); DebugP_assert(status == SystemP_SUCCESS); } } else { /* Register & enable ICSSG EnDat PRU FW interrupt */ HwiP_Params_init(&hwiPrms); hwiPrms.intNum = ICSSG_PRU_ENDAT_INT_NUM; hwiPrms.callback = &pruEnDatIrqHandler0; hwiPrms.args = 0; hwiPrms.isPulse = FALSE; hwiPrms.isFIQ = FALSE; status = HwiP_construct(&gIcssgEncoderHwiObject0, &hwiPrms); DebugP_assert(status == SystemP_SUCCESS); } } uint32_t endat_config_periodic_mode(struct endat_periodic_interface *endat_periodic_interface, PRUICSS_Handle handle) { int32_t status; gPruIcssXHandle = handle; gPruss_iep = endat_periodic_interface->pruss_iep; /*configure IEP*/ endat_config_iep(endat_periodic_interface); /* Initialize ICSS INTC */ status = PRUICSS_intcInit(gPruIcssXHandle, &gPruicssIntcInitdata); if (status != SystemP_SUCCESS) { return 0; } /*config Interrupt*/ endat_interrupt_config(endat_periodic_interface); return 1; } void endat_stop_periodic_continuous_mode(struct endat_periodic_interface *endat_periodic_interface) { /*reset iep timer*/ void *pruss_iep = endat_periodic_interface->pruss_iep; uint8_t temp; /*clear IEP*/ temp = HW_RD_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_GLOBAL_CFG_REG ); temp &= 0xFE; HW_WR_REG8((uint8_t*)pruss_iep + CSL_ICSS_G_PR1_IEP1_SLV_GLOBAL_CFG_REG, temp); } /* PRU EnDat FW IRQ handler */ void pruEnDatIrqHandler0(void *args) { /* debug, inncrement PRU SDFM IRQ count */ gPruEnDatIrqCnt0++; /* Clear interrupt at source */ /* Write 18 to ICSSG_STATUS_CLR_INDEX_REG Firmware: TRIGGER_HOST_SDFM_IRQ defined as 18 18 = 16+2, 2 is Host Interrupt Number. See AM64x TRM. */ PRUICSS_clearEvent(gPruIcssXHandle, PRU_TRIGGER_HOST_SDFM_EVT0); } /* PRU EnDat FW IRQ handler */ void pruEnDatIrqHandler1(void *args) { /* debug, inncrement PRU SDFM IRQ count */ gPruEnDatIrqCnt1++; /* Clear interrupt at source */ /* Write 18 to ICSSG_STATUS_CLR_INDEX_REG Firmware: TRIGGER_HOST_SDFM_IRQ defined as 18 18 = 16+2, 2 is Host Interrupt Number. See AM64x TRM. */ PRUICSS_clearEvent(gPruIcssXHandle, PRU_TRIGGER_HOST_SDFM_EVT1); } /* PRU EnDat FW IRQ handler */ void pruEnDatIrqHandler2(void *args) { /* debug, inncrement PRU SDFM IRQ count */ gPruEnDatIrqCnt2++; /* Clear interrupt at source */ /* Write 18 to ICSSG_STATUS_CLR_INDEX_REG Firmware: TRIGGER_HOST_SDFM_IRQ defined as 18 18 = 16+2, 2 is Host Interrupt Number. See AM64x TRM. */ PRUICSS_clearEvent(gPruIcssXHandle, PRU_TRIGGER_HOST_SDFM_EVT2); }