| /* 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; |
| |
| } |