/* Copyright (c) 2013-2014, 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 #include #include #include #include #include #include #include #include #include #include #include #include static int ufs_dev_init(struct ufs_dev *dev) { /* Init the mutexes. */ mutex_init(&(dev->uic_data.uic_mutex)); mutex_init(&(dev->utrd_data.bitmap_mutex)); mutex_init(&(dev->utmrd_data.bitmap_mutex)); /* Initialize wait lists. */ list_initialize(&(dev->utrd_data.list_head.list_node)); list_initialize(&(dev->utmrd_data.list_head.list_node)); /* Initialize the bitmaps. */ dev->utrd_data.bitmap = 0; dev->utmrd_data.bitmap = 0; /* Initialize task ids. */ dev->utrd_data.task_id = 0; dev->utmrd_data.task_id = 0; /* Allocate memory for lists. */ dev->utrd_data.list_base_addr = ufs_alloc_trans_req_list(); dev->utmrd_data.list_base_addr = ufs_alloc_task_mgmt_req_list(); if (!dev->utrd_data.list_base_addr || !dev->utmrd_data.list_base_addr) return -UFS_FAILURE; return UFS_SUCCESS; } static void ufs_setup_req_lists(struct ufs_dev *dev) { uint32_t val; writel(dev->utmrd_data.list_base_addr, UFS_UTMRLBA(dev->base)); writel(dev->utmrd_data.list_base_addr << 32, UFS_UTMRLBAU(dev->base)); writel(dev->utrd_data.list_base_addr, UFS_UTRLBA(dev->base)); writel(dev->utrd_data.list_base_addr << 32, UFS_UTRLBAU(dev->base)); writel(1, UFS_UTMRLRSR(dev->base)); writel(1, UFS_UTRLRSR(dev->base)); /* Enable the required irqs. */ val = UFS_IE_UEE | UFS_IE_UCCE ; ufs_irq_enable(dev, val); // Change UFS_IRQ to level based qgic_change_interrupt_cfg(UFS_IRQ, INTERRUPT_LVL_N_TO_N); } void ufs_rpmb_init(struct ufs_dev *dev) { int ret = 0; /* * Perform request sense on lun to clear * attention pending, other wise all the read/write * operations would fail with check condition error */ ucs_do_request_sense(dev, UFS_WLUN_RPMB); // calculate the size of rpmb partition in sectors ret = dme_read_unit_desc(dev, UFS_WLUN_RPMB); if (ret != UFS_SUCCESS) { dprintf(CRITICAL, "UFS dme_read_unit_desc failed for RPMB Partition\n"); return; } // gets the number of rpmb frames allowed in a single UPIU commands ret = dme_read_geo_desc(dev); if (ret != UFS_SUCCESS) { dprintf(CRITICAL, "UFS dme_read_geo_desc failed for RPMB Partition\n"); return; } #ifdef DEBUG_UFS dprintf(INFO, "RPMB: Logical Block Count: 0x%x\n", dev->rpmb_num_blocks); dprintf(INFO, "RPMB: RPMB Read Write Size: 0x%x\n", dev->rpmb_rw_size); #endif } int ufs_read(struct ufs_dev* dev, uint64_t start_lba, addr_t buffer, uint32_t num_blocks) { struct scsi_rdwr_req req; int ret; req.data_buffer_base = buffer; req.lun = dev->current_lun; req.num_blocks = num_blocks; req.start_lba = start_lba / dev->block_size; ret = ucs_do_scsi_read(dev, &req); if (ret) { dprintf(CRITICAL, "UFS read failed.\n"); ufs_dump_hc_registers(dev); } return ret; } int ufs_write(struct ufs_dev* dev, uint64_t start_lba, addr_t buffer, uint32_t num_blocks) { struct scsi_rdwr_req req; int ret; req.data_buffer_base = buffer; req.lun = dev->current_lun; req.num_blocks = num_blocks; req.start_lba = start_lba / dev->block_size; ret = ucs_do_scsi_write(dev, &req); if (ret) { dprintf(CRITICAL, "UFS write failed.\n"); ufs_dump_hc_registers(dev); } return ret; } int ufs_erase(struct ufs_dev* dev, uint64_t start_lba, uint32_t num_blocks) { struct scsi_unmap_req req; int ret; req.lun = dev->current_lun; req.start_lba = start_lba / dev->block_size; req.num_blocks = num_blocks; ret = ucs_do_scsi_unmap(dev, &req); if(ret) { dprintf(CRITICAL, "UFS erase failed \n"); } return ret; } uint64_t ufs_get_dev_capacity(struct ufs_dev* dev) { uint64_t capacity; uint8_t lun = dev->current_lun; capacity = dev->lun_cfg[lun].logical_blk_cnt * dev->block_size; return capacity; } uint32_t ufs_get_erase_blk_size(struct ufs_dev* dev) { uint32_t erase_blk_size; uint8_t lun = dev->current_lun; erase_blk_size = dev->lun_cfg[lun].erase_blk_size; return erase_blk_size; } uint32_t ufs_get_serial_num(struct ufs_dev* dev) { int ret; ret = dme_read_device_desc(dev); if (ret) { dprintf(CRITICAL, "UFS get serial number failed.\n"); ufs_dump_hc_registers(dev); } return dev->serial_num; } uint32_t ufs_get_page_size(struct ufs_dev* dev) { return dev->block_size; } uint8_t ufs_get_num_of_luns(struct ufs_dev* dev) { return dev->num_lus; } int ufs_init(struct ufs_dev *dev) { uint32_t ret = UFS_SUCCESS; uint8_t lun = 0; dev->block_size = 4096; /* Init dev struct. */ ret = ufs_dev_init(dev); if (ret != UFS_SUCCESS) { dprintf(CRITICAL, "UFS dev_init failed\n"); goto ufs_init_err; } /* Perform Data link init. */ ret = uic_init(dev); if (ret != UFS_SUCCESS) { dprintf(CRITICAL, "UFS uic_init failed\n"); goto ufs_init_err; } /* Setup request lists. */ ufs_setup_req_lists(dev); /* Send NOP to check if device UTP layer is ready. */ ret = dme_send_nop_query(dev); if (ret != UFS_SUCCESS) { dprintf(CRITICAL, "UFS dme_send_nop_query failed\n"); goto ufs_init_err; } ret = dme_set_fdeviceinit(dev); if (ret != UFS_SUCCESS) { dprintf(CRITICAL, "UFS dme_set_fdeviceinit failed\n"); goto ufs_init_err; } ret = ucs_scsi_send_inquiry(dev); if (ret != UFS_SUCCESS) { dprintf(CRITICAL, "UFS ucs_scsi_send_inquiry failed\n"); goto ufs_init_err; } ret = dme_read_device_desc(dev); if (ret != UFS_SUCCESS) { dprintf(CRITICAL, "dme_read_dev_desc read failed\n"); goto ufs_init_err; } for(lun=0; lun < dev->num_lus; lun++) { ret = dme_read_unit_desc(dev, lun); if (ret != UFS_SUCCESS) { dprintf(CRITICAL, "UFS dme_read_unit_desc failed\n"); goto ufs_init_err; } } dprintf(CRITICAL,"UFS init success\n"); ufs_init_err: if(ret != UFS_SUCCESS) { ufs_dump_hc_registers(dev); } return ret; } void ufs_dump_is_register(struct ufs_dev *dev) { uint32_t base = dev->base; dprintf(CRITICAL,"UFS_IS 0x%x\n",readl(UFS_IS(base))); } void ufs_dump_hc_registers(struct ufs_dev *dev) { uint32_t base = dev->base; dprintf(CRITICAL,"------Host controller register dump ---------\n"); dprintf(CRITICAL,"UFS_UECPA 0x%x\n",readl(UFS_UECPA(base))); dprintf(CRITICAL,"UFS_UECDL 0x%x\n",readl(UFS_UECDL(base))); dprintf(CRITICAL,"UFS_UECN 0x%x\n", readl(UFS_UECN(base))); dprintf(CRITICAL,"UFS_UECT 0x%x\n",readl(UFS_UECT(base))); dprintf(CRITICAL,"UFS_UECDME 0x%x\n",readl(UFS_UECDME(base))); dprintf(CRITICAL,"UFS_HCS 0x%x\n", readl(UFS_HCS(base))); dprintf(CRITICAL,"-----------End--------------------------------\n"); }