158 lines
4.9 KiB
C
158 lines
4.9 KiB
C
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
|
|
|
* 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 The Linux Foundation, 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 "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
|
* 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 <pm_fg_sram.h>
|
|
#include <pm8x41.h>
|
|
#include <pm8x41_hw.h>
|
|
#include <debug.h>
|
|
#include <bits.h>
|
|
#include <platform/timer.h>
|
|
#include <pm_comm.h>
|
|
|
|
static int fg_check_addr_mask(int sid,uint32_t addr,uint8_t mask,uint8_t set)
|
|
{
|
|
uint8_t value;
|
|
int ret = 1;
|
|
int try = FG_MAX_TRY;
|
|
|
|
udelay(30);
|
|
while(try)
|
|
{
|
|
ret = pm_comm_read_byte_mask(sid, addr, mask, &value, 0);
|
|
if( !ret && (value == set) )
|
|
goto err;
|
|
|
|
udelay(1000);
|
|
try--;
|
|
}
|
|
err:
|
|
return ret;
|
|
}
|
|
|
|
int pmi_fg_sram_read(uint32_t addr, uint32_t *data,int sid, uint8_t offset, uint8_t len)
|
|
{
|
|
uint8_t value;
|
|
int err = 0;
|
|
uint8_t start_beat_count, end_beat_count;
|
|
|
|
if(offset > 3)
|
|
{
|
|
dprintf(INFO,"offset beyond the 4 byte boundary\n");
|
|
goto err;
|
|
}
|
|
/* poll to check if fg memif is available */
|
|
err = fg_check_addr_mask(sid,FG_MEMIF_MEM_INTF_CFG, RIF_MEM_ACCESS_REQ, 0);
|
|
if(err)
|
|
{
|
|
dprintf(INFO,"Failed to get fg sram access\n");
|
|
goto err;
|
|
}
|
|
|
|
/* enter into ima mode write 8'hA0 */
|
|
pm_comm_write_byte(sid, FG_MEMIF_MEM_INTF_CFG, 0xA0, 0);
|
|
/* ensure single read access 8'h00 */
|
|
pm_comm_write_byte(sid, FG_MEMIF_MEM_INTF_CTL, 0x00, 0);
|
|
|
|
/* poll ima is ready */
|
|
err = fg_check_addr_mask(sid, FG_MEMIF_IMA_OPERATION_STS, IACS_RDY, 1);
|
|
if(err)
|
|
{
|
|
dprintf(INFO,"IACS is not ready cannot enter ima mode\n");
|
|
goto err;
|
|
}
|
|
|
|
/* write lsb address of the requested data */
|
|
value = addr & 0xff;
|
|
pm_comm_write_byte(sid, FG_MEMIF_MEM_INTF_ADDR_LSB, value, 0);
|
|
|
|
/* write msb address of the requested data */
|
|
value = (addr >> 8) & 0xff;
|
|
pm_comm_write_byte(sid, FG_MEMIF_MEM_INTF_ADDR_MSB, value, 0);
|
|
|
|
/* poll until transaction is completed */
|
|
/* poll ima is ready */
|
|
err = fg_check_addr_mask(sid, FG_MEMIF_IMA_OPERATION_STS, IACS_RDY, 1);
|
|
if(err)
|
|
{
|
|
dprintf(INFO,"IACS is not ready cannot set address\n");
|
|
goto err;
|
|
}
|
|
|
|
/* read start beat count */
|
|
pm_comm_read_byte_mask(sid, FG_MEMIF_FG_BEAT_COUNT, BEAT_COUNT_MASK, &start_beat_count, 0);
|
|
/* read the data */
|
|
pm_comm_read_byte(sid, FG_MEMIF_MEM_INTF_RD_DATA0, &value, 0);
|
|
*data = value;
|
|
pm_comm_read_byte(sid, FG_MEMIF_MEM_INTF_RD_DATA1, &value, 0);
|
|
*data |= value << 8;
|
|
pm_comm_read_byte(sid, FG_MEMIF_MEM_INTF_RD_DATA2, &value, 0);
|
|
*data |= value << 16;
|
|
pm_comm_read_byte(sid, FG_MEMIF_MEM_INTF_RD_DATA3, &value, 0);
|
|
*data = value << 24;
|
|
|
|
/* poll to check there was no error */
|
|
err = fg_check_addr_mask(sid, FG_MEMIF_IMA_OPERATION_STS, IACS_RDY, 1);
|
|
if(err)
|
|
{
|
|
dprintf(INFO,"IACS is not ready cannot read\n");
|
|
goto err;
|
|
}
|
|
|
|
pm_comm_read_byte(sid, FG_MEMIF_IMA_EXCEPTION_STS, &value, 0);
|
|
err = value;
|
|
if(!err)
|
|
{
|
|
*data = ((*data) >> (offset*8)) & (FG_DATA_MASK >> ((FG_DATA_MAX_LEN - len)*8) );
|
|
pm_comm_read_byte_mask(sid, FG_MEMIF_FG_BEAT_COUNT, BEAT_COUNT_MASK, &end_beat_count, 0);
|
|
if(start_beat_count != end_beat_count)
|
|
err = 1;
|
|
}
|
|
else
|
|
{
|
|
/* error occured */
|
|
/*perform iacs clear sequence 1'b1 */
|
|
pm_comm_read_byte(sid, FG_MEMIF_IMA_CFG, &value, 0);
|
|
value |= IACS_CLR;
|
|
pm_comm_write_byte(sid, FG_MEMIF_IMA_CFG, value, 0);
|
|
/* 8'h04 */
|
|
pm_comm_write_byte(sid, FG_MEMIF_MEM_INTF_ADDR_MSB, 0x04, 0);
|
|
/* 8'h00 */
|
|
pm_comm_write_byte(sid, FG_MEMIF_MEM_INTF_WR_DATA3, 0x00, 0);
|
|
pm_comm_read_byte(sid, FG_MEMIF_MEM_INTF_RD_DATA3, &value, 0);
|
|
/*perform iacs clear sequence 1'b0 */
|
|
pm_comm_read_byte(sid, FG_MEMIF_IMA_CFG, &value, 0);
|
|
value &= ~(IACS_CLR);
|
|
pm_comm_write_byte(sid, FG_MEMIF_IMA_CFG, value, 0);
|
|
}
|
|
|
|
err:
|
|
pm_comm_write_byte(sid, FG_MEMIF_MEM_INTF_CFG, 0x00, 0);
|
|
|
|
return err;
|
|
|
|
}
|