12c3d2faaSYifeng Zhao // SPDX-License-Identifier: GPL-2.0+ 22c3d2faaSYifeng Zhao /* 32c3d2faaSYifeng Zhao * Rockchip UFS Host Controller driver 42c3d2faaSYifeng Zhao * 52c3d2faaSYifeng Zhao * Copyright (C) 2024 Rockchip Electronics Co.Ltd. 62c3d2faaSYifeng Zhao */ 72c3d2faaSYifeng Zhao 82c3d2faaSYifeng Zhao #include <charset.h> 92c3d2faaSYifeng Zhao #include <common.h> 102c3d2faaSYifeng Zhao #include <dm.h> 112c3d2faaSYifeng Zhao #include <log.h> 122c3d2faaSYifeng Zhao #include <dm/lists.h> 132c3d2faaSYifeng Zhao #include <dm/device-internal.h> 142c3d2faaSYifeng Zhao #include <malloc.h> 152c3d2faaSYifeng Zhao #include <hexdump.h> 162c3d2faaSYifeng Zhao #include <scsi.h> 172c3d2faaSYifeng Zhao #include <asm/io.h> 182c3d2faaSYifeng Zhao #include <asm/dma-mapping.h> 192c3d2faaSYifeng Zhao #include <linux/bitops.h> 202c3d2faaSYifeng Zhao #include <linux/delay.h> 212c3d2faaSYifeng Zhao 222c3d2faaSYifeng Zhao #include "ufs-rockchip-usbplug.h" 232c3d2faaSYifeng Zhao #include "ufs.h" 241e6560dfSYifeng Zhao /* Query request retries */ 251e6560dfSYifeng Zhao #define QUERY_REQ_RETRIES 3 261e6560dfSYifeng Zhao /* Query request timeout */ 271e6560dfSYifeng Zhao #define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */ 282c3d2faaSYifeng Zhao 292c3d2faaSYifeng Zhao #if defined(CONFIG_SUPPORT_USBPLUG) 302c3d2faaSYifeng Zhao int _ufs_start(struct ufs_hba *hba); 312c3d2faaSYifeng Zhao 322c3d2faaSYifeng Zhao static void ufs_info_show_dev_desc(void *buf) 332c3d2faaSYifeng Zhao { 342c3d2faaSYifeng Zhao struct ufs_device_descriptor *dev = (struct ufs_device_descriptor *)buf; 352c3d2faaSYifeng Zhao 362c3d2faaSYifeng Zhao printf("---------------------------\n"); 372c3d2faaSYifeng Zhao printf("---UFS Device Descriptor---\n"); 382c3d2faaSYifeng Zhao printf("---------------------------\n"); 392c3d2faaSYifeng Zhao printf("bLength: 0x%x\n", dev->b_length); 402c3d2faaSYifeng Zhao printf("bDescriptorIDN: 0x%x\n", dev->b_descriptor_idn); 412c3d2faaSYifeng Zhao printf("bDevice: 0x%x\n", dev->b_device); 422c3d2faaSYifeng Zhao printf("bDeviceClass: 0x%x\n", dev->b_device_class); 432c3d2faaSYifeng Zhao printf("bDeviceSubClass: 0x%x\n", dev->b_device_sub_class); 442c3d2faaSYifeng Zhao printf("bProtocol: 0x%x\n", dev->b_protocol); 452c3d2faaSYifeng Zhao printf("bNumberLU: 0x%x\n", dev->b_number_lu); 462c3d2faaSYifeng Zhao printf("bNumberWLU: 0x%x\n", dev->b_number_wlu); 472c3d2faaSYifeng Zhao printf("bBootEnable: 0x%x\n", dev->b_boot_enable); 482c3d2faaSYifeng Zhao printf("bDescrAccessEn: 0x%x\n", dev->b_descr_access_en); 492c3d2faaSYifeng Zhao printf("bInitPowerMode: 0x%x\n", dev->b_init_power_mode); 502c3d2faaSYifeng Zhao printf("bHighPriorityLUN: 0x%x\n", dev->b_high_priority_lun); 512c3d2faaSYifeng Zhao printf("bSecureRemovalType: 0x%x\n", dev->b_secure_removal_type); 522c3d2faaSYifeng Zhao printf("bSecurityLU: 0x%x\n", dev->b_security_lu); 532c3d2faaSYifeng Zhao printf("bBackgroundOpsTermLat: 0x%x\n", dev->b_background_ops_term_lat); 542c3d2faaSYifeng Zhao printf("bInitActiveICCLevel: 0x%x\n", dev->b_init_active_icc_level); 552c3d2faaSYifeng Zhao printf("wSpecVersion: 0x%x\n", to_bigendian16(dev->w_spec_version)); 562c3d2faaSYifeng Zhao printf("wManufactureDate: 0x%x\n", to_bigendian16(dev->w_manufacture_date)); 572c3d2faaSYifeng Zhao printf("iManufacturerName: 0x%x\n", dev->i_manufacturer_name); 582c3d2faaSYifeng Zhao printf("iProductName: 0x%x\n", dev->i_product_name); 592c3d2faaSYifeng Zhao printf("iSerialNumber: 0x%x\n", dev->i_serial_number); 602c3d2faaSYifeng Zhao printf("iOemID: 0x%x\n", dev->i_oem_id); 612c3d2faaSYifeng Zhao printf("wManufacturerID: 0x%x\n", to_bigendian16(dev->w_manufacturer_id)); 622c3d2faaSYifeng Zhao printf("bUD0BaseOffset: 0x%x\n", dev->b_ud_0base_offset); 632c3d2faaSYifeng Zhao printf("bUDConfigPLength: 0x%x\n", dev->b_ud_config_plength); 642c3d2faaSYifeng Zhao printf("bDeviceRTTCap: 0x%x\n", dev->b_device_rtt_cap); 652c3d2faaSYifeng Zhao printf("wPeriodicRTCUpdate: 0x%x\n", to_bigendian16(dev->w_periodic_rtc_update)); 662c3d2faaSYifeng Zhao printf("bUFSFeatureSupport: 0x%x\n", dev->b_ufs_feature_support); 672c3d2faaSYifeng Zhao printf("bFFUTimeout: 0x%x\n", dev->b_ffu_timeout); 682c3d2faaSYifeng Zhao printf("bQueueDepth: 0x%x\n", dev->b_queue_depth); 692c3d2faaSYifeng Zhao printf("wDeviceVersion: 0x%x\n", to_bigendian16(dev->w_device_version)); 702c3d2faaSYifeng Zhao printf("bNumSecureWPArea: 0x%x\n", dev->b_num_secure_wp_area); 712c3d2faaSYifeng Zhao printf("dPSAMaxDataSize: 0x%x\n", to_bigendian32(dev->d_psa_max_data_size)); 722c3d2faaSYifeng Zhao printf("bPSAStateTimeout: 0x%x\n", dev->b_psa_state_timeout); 732c3d2faaSYifeng Zhao printf("iProductRevisionLevel: 0x%x\n", dev->i_product_revision_level); 742c3d2faaSYifeng Zhao } 752c3d2faaSYifeng Zhao 762c3d2faaSYifeng Zhao static void ufs_info_show_conf_desc(void *buf) 772c3d2faaSYifeng Zhao { 782c3d2faaSYifeng Zhao struct ufs_configuration_descriptor *c_desc = (struct ufs_configuration_descriptor *)buf; 792c3d2faaSYifeng Zhao struct ufs_dev_desc_configuration_param *dev; 802c3d2faaSYifeng Zhao struct ufs_unit_desc_configuration_param *unit; 812c3d2faaSYifeng Zhao int i; 822c3d2faaSYifeng Zhao 832c3d2faaSYifeng Zhao dev = &c_desc->dev_desc_conf_param; 842c3d2faaSYifeng Zhao printf("----------------------------------------\n"); 852c3d2faaSYifeng Zhao printf("---UFS Device Descriptor Config Param---\n"); 862c3d2faaSYifeng Zhao printf("----------------------------------------\n"); 872c3d2faaSYifeng Zhao printf("bLength: 0x%x\n", dev->b_length); 882c3d2faaSYifeng Zhao printf("bDescriptorIDN: 0x%x\n", dev->b_descriptor_idn); 892c3d2faaSYifeng Zhao printf("bConfDescContinue: 0x%x\n", dev->b_conf_desc_continue); 902c3d2faaSYifeng Zhao printf("bBootEnable: 0x%x\n", dev->b_boot_enable); 912c3d2faaSYifeng Zhao printf("bDescrAccessEn: 0x%x\n", dev->b_descr_access_en); 922c3d2faaSYifeng Zhao printf("bInitPowerMode: 0x%x\n", dev->b_init_power_mode); 932c3d2faaSYifeng Zhao printf("bHighPriorityLUN: 0x%x\n", dev->b_high_priority_lun); 942c3d2faaSYifeng Zhao printf("bSecureRemovalType: 0x%x\n", dev->b_secure_removal_type); 952c3d2faaSYifeng Zhao printf("bInitActiveICCLevel: 0x%x\n", dev->b_init_active_icc_level); 962c3d2faaSYifeng Zhao printf("wPeriodicRTCUpdate: 0x%x\n", to_bigendian16(dev->w_periodic_rtc_update)); 97*1865a7e4SYifeng Zhao printf("bSecureRemovalType: 0x%x\n", dev->b_secure_removal_type); 98*1865a7e4SYifeng Zhao printf("bInitActiveICCLevel: 0x%x\n", dev->b_init_active_icc_level); 99*1865a7e4SYifeng Zhao printf("wPeriodicRTCUpdate: 0x%x\n", to_bigendian16(dev->w_periodic_rtc_update)); 100*1865a7e4SYifeng Zhao printf("bWB_EN: 0x%x\n", dev->b_write_booster_buffer_reserve_user_space_en); 101*1865a7e4SYifeng Zhao printf("WB_TYPE: 0x%x\n", dev->b_write_booster_buffer_type); 102*1865a7e4SYifeng Zhao printf("WB_alloc_units: 0x%x\n", to_bigendian32(dev->d_num_shared_write_booster_buffer_alloc_units)); 1032c3d2faaSYifeng Zhao 1042c3d2faaSYifeng Zhao for (i = 0; i < UNIT_DESCS_COUNT; i++) { 1052c3d2faaSYifeng Zhao unit = &c_desc->unit_desc_conf_param[i]; 1062c3d2faaSYifeng Zhao 1072c3d2faaSYifeng Zhao printf("-----------------------------------------\n"); 1082c3d2faaSYifeng Zhao printf("---UFS Unit %d Descriptor Config Param---\n", i); 1092c3d2faaSYifeng Zhao printf("-----------------------------------------\n"); 1102c3d2faaSYifeng Zhao printf("bLUEnable: 0x%x\n", unit->b_lu_enable); 1112c3d2faaSYifeng Zhao printf("bBootLunID: 0x%x\n", unit->b_boot_lun_id); 1122c3d2faaSYifeng Zhao printf("bLUWriteProtect: 0x%x\n", unit->b_lu_write_protect); 1132c3d2faaSYifeng Zhao printf("bMemoryType: 0x%x\n", unit->b_memory_type); 1142c3d2faaSYifeng Zhao printf("dNumAllocUnits: 0x%x\n", to_bigendian32(unit->d_num_alloc_units)); 1152c3d2faaSYifeng Zhao printf("bDataReliability: 0x%x\n", unit->b_data_reliability); 1162c3d2faaSYifeng Zhao printf("bLogicalBlockSize: 0x%x\n", unit->b_logical_block_size); 1172c3d2faaSYifeng Zhao printf("bProvisioningType: 0x%x\n", unit->b_provisioning_type); 1182c3d2faaSYifeng Zhao printf("wContextCapabilities: 0x%x\n", to_bigendian16(unit->w_context_capabilities)); 1192c3d2faaSYifeng Zhao } 1202c3d2faaSYifeng Zhao } 1212c3d2faaSYifeng Zhao 1222c3d2faaSYifeng Zhao static int ufs_get_configuration_desc(struct ufs_hba *hba, struct ufs_configuration_descriptor *c_desc) 1232c3d2faaSYifeng Zhao { 1242c3d2faaSYifeng Zhao u8 desc_buf[CONFIGURATION_DESC_V22_LENGTH]; 1252c3d2faaSYifeng Zhao u8 *buf = desc_buf; 1262c3d2faaSYifeng Zhao int length = CONFIGURATION_DESC_V22_LENGTH; 1272c3d2faaSYifeng Zhao int err; 1282c3d2faaSYifeng Zhao 1292c3d2faaSYifeng Zhao if (CONFIGURATION_DESC_V31_LENGTH == hba->desc_size.conf_desc) { 1302c3d2faaSYifeng Zhao buf = (u8 *)c_desc; 1312c3d2faaSYifeng Zhao length = CONFIGURATION_DESC_V31_LENGTH; 1322c3d2faaSYifeng Zhao } else if(CONFIGURATION_DESC_V22_LENGTH != hba->desc_size.conf_desc) { 1332c3d2faaSYifeng Zhao return -EINVAL; 1342c3d2faaSYifeng Zhao } 1352c3d2faaSYifeng Zhao 1362c3d2faaSYifeng Zhao err = ufshcd_read_desc_param(hba, QUERY_DESC_IDN_CONFIGURATION, 0, 0, buf, length); 1372c3d2faaSYifeng Zhao if (err) { 1382c3d2faaSYifeng Zhao dev_err(hba->dev, "%s: Failed reading configuration Desc. err = %d\n", 1392c3d2faaSYifeng Zhao __func__, err); 1402c3d2faaSYifeng Zhao return err; 1412c3d2faaSYifeng Zhao } 1422c3d2faaSYifeng Zhao 1432c3d2faaSYifeng Zhao if (CONFIGURATION_DESC_V22_LENGTH == hba->desc_size.conf_desc) { 1442c3d2faaSYifeng Zhao memcpy(&c_desc->dev_desc_conf_param, buf, 0x10); 1452c3d2faaSYifeng Zhao buf += 0x10; 1462c3d2faaSYifeng Zhao for (int i = 0; i < UNIT_DESCS_COUNT; i++) { 1472c3d2faaSYifeng Zhao memcpy(&c_desc->unit_desc_conf_param[i], buf, 0x10); 1482c3d2faaSYifeng Zhao buf += 0x10; 1492c3d2faaSYifeng Zhao } 1502c3d2faaSYifeng Zhao } 1512c3d2faaSYifeng Zhao 1522c3d2faaSYifeng Zhao return err; 1532c3d2faaSYifeng Zhao } 1542c3d2faaSYifeng Zhao 1552c3d2faaSYifeng Zhao static int ufshcd_write_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, 1562c3d2faaSYifeng Zhao int desc_index, u8 param_offset, u8 *param_read_buf, 1572c3d2faaSYifeng Zhao u8 param_size) 1582c3d2faaSYifeng Zhao { 1592c3d2faaSYifeng Zhao int ret; 1602c3d2faaSYifeng Zhao u8 *desc_buf; 1612c3d2faaSYifeng Zhao int buff_len; 1622c3d2faaSYifeng Zhao 1632c3d2faaSYifeng Zhao /* Safety check */ 1642c3d2faaSYifeng Zhao if (desc_id >= QUERY_DESC_IDN_MAX || !param_size) 1652c3d2faaSYifeng Zhao return -EINVAL; 1662c3d2faaSYifeng Zhao 1672c3d2faaSYifeng Zhao /* Get the max length of descriptor from structure filled up at probe 1682c3d2faaSYifeng Zhao * time. 1692c3d2faaSYifeng Zhao */ 1702c3d2faaSYifeng Zhao ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len); 1712c3d2faaSYifeng Zhao 1722c3d2faaSYifeng Zhao /* Sanity checks */ 1732c3d2faaSYifeng Zhao if (ret || !buff_len) { 1742c3d2faaSYifeng Zhao dev_err(hba->dev, "%s: Failed to get full descriptor length\n", 1752c3d2faaSYifeng Zhao __func__); 1762c3d2faaSYifeng Zhao return ret; 1772c3d2faaSYifeng Zhao } 1782c3d2faaSYifeng Zhao 1792c3d2faaSYifeng Zhao desc_buf = param_read_buf; 1802c3d2faaSYifeng Zhao /* Request for full descriptor */ 1812c3d2faaSYifeng Zhao ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_WRITE_DESC, 1822c3d2faaSYifeng Zhao desc_id, desc_index, 0, desc_buf, 1832c3d2faaSYifeng Zhao &buff_len); 1842c3d2faaSYifeng Zhao 1852c3d2faaSYifeng Zhao if (ret) 1862c3d2faaSYifeng Zhao dev_err(hba->dev, "%s: Failed write descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n", 1872c3d2faaSYifeng Zhao __func__, desc_id, desc_index, param_offset, ret); 1882c3d2faaSYifeng Zhao 1892c3d2faaSYifeng Zhao return ret; 1902c3d2faaSYifeng Zhao } 1912c3d2faaSYifeng Zhao 1922c3d2faaSYifeng Zhao static int ufs_write_configuration_desc(struct ufs_hba *hba, struct ufs_configuration_descriptor *c_desc) 1932c3d2faaSYifeng Zhao { 1942c3d2faaSYifeng Zhao u8 desc_buf[CONFIGURATION_DESC_V22_LENGTH]; 1952c3d2faaSYifeng Zhao u8 *buf = desc_buf; 1962c3d2faaSYifeng Zhao int length = CONFIGURATION_DESC_V22_LENGTH; 1972c3d2faaSYifeng Zhao int err; 1982c3d2faaSYifeng Zhao 1992c3d2faaSYifeng Zhao if (CONFIGURATION_DESC_V31_LENGTH == hba->desc_size.conf_desc) { 2002c3d2faaSYifeng Zhao buf = (u8 *)c_desc; 2012c3d2faaSYifeng Zhao length = CONFIGURATION_DESC_V31_LENGTH; 2022c3d2faaSYifeng Zhao } else if(CONFIGURATION_DESC_V22_LENGTH == hba->desc_size.conf_desc) { 2032c3d2faaSYifeng Zhao memcpy(buf, &c_desc->dev_desc_conf_param, 0x10); 2042c3d2faaSYifeng Zhao buf += 0x10; 2052c3d2faaSYifeng Zhao for (int i = 0; i < UNIT_DESCS_COUNT; i++) { 2062c3d2faaSYifeng Zhao memcpy(buf, &c_desc->unit_desc_conf_param[i], 0x10); 2072c3d2faaSYifeng Zhao buf += 0x10; 2082c3d2faaSYifeng Zhao } 2092c3d2faaSYifeng Zhao buf = desc_buf; 2102c3d2faaSYifeng Zhao } else { 2112c3d2faaSYifeng Zhao return -EINVAL; 2122c3d2faaSYifeng Zhao } 2132c3d2faaSYifeng Zhao 2142c3d2faaSYifeng Zhao err = ufshcd_write_desc_param(hba, QUERY_DESC_IDN_CONFIGURATION, 0, 0, buf, length); 2152c3d2faaSYifeng Zhao if (err) { 2162c3d2faaSYifeng Zhao dev_err(hba->dev, "%s: Failed reading configuration Desc. err = %d\n", 2172c3d2faaSYifeng Zhao __func__, err); 2182c3d2faaSYifeng Zhao return err; 2192c3d2faaSYifeng Zhao } 2202c3d2faaSYifeng Zhao 2212c3d2faaSYifeng Zhao return err; 2222c3d2faaSYifeng Zhao } 2232c3d2faaSYifeng Zhao 2242c3d2faaSYifeng Zhao static void ufs_lu_configuration(struct ufs_hba *hba, struct ufs_configuration_descriptor *c_desc) 2252c3d2faaSYifeng Zhao { 2262c3d2faaSYifeng Zhao uint32_t denominator = hba->geo_desc->b_allocation_unit_size * to_bigendian32(hba->geo_desc->d_segment_size); 2272c3d2faaSYifeng Zhao struct ufs_dev_desc_configuration_param *dev; 2282c3d2faaSYifeng Zhao struct ufs_unit_desc_configuration_param *unit; 2292c3d2faaSYifeng Zhao uint32_t alloced_units = 0; 2302c3d2faaSYifeng Zhao int i, cap_adj_fac; 2312c3d2faaSYifeng Zhao uint64_t total_raw_device_capacity; 232*1865a7e4SYifeng Zhao uint32_t max_wb_alloc_units = cpu_to_be32(hba->geo_desc->d_write_booster_buffer_max_alloc_units); 233*1865a7e4SYifeng Zhao uint32_t wb_alloc_units; 2342c3d2faaSYifeng Zhao 2352c3d2faaSYifeng Zhao cap_adj_fac = to_bigendian16(hba->geo_desc->w_enhanced1_cap_adj_fac) / 256; 2362c3d2faaSYifeng Zhao total_raw_device_capacity = cpu_to_be64(hba->geo_desc->q_total_raw_device_capacity); 2372c3d2faaSYifeng Zhao 2382c3d2faaSYifeng Zhao dev = &c_desc->dev_desc_conf_param; 2392c3d2faaSYifeng Zhao dev->b_boot_enable = 0x1; 2402c3d2faaSYifeng Zhao dev->b_descr_access_en = 0x0; 2412c3d2faaSYifeng Zhao dev->b_init_power_mode = 0x1; 2422c3d2faaSYifeng Zhao dev->b_high_priority_lun = 0x7F; 2432c3d2faaSYifeng Zhao dev->b_secure_removal_type = 0x0; 2442c3d2faaSYifeng Zhao dev->b_init_active_icc_level = 0x0; 2452c3d2faaSYifeng Zhao dev->w_periodic_rtc_update = 0x0; 2462c3d2faaSYifeng Zhao 2472c3d2faaSYifeng Zhao unit = &c_desc->unit_desc_conf_param[0]; 2482c3d2faaSYifeng Zhao /* lu 1: boot lu A 4MB */ 2492c3d2faaSYifeng Zhao unit[1].b_boot_lun_id = WELL_BOOT_LU_A; /* lu 0, boot a */ 2502c3d2faaSYifeng Zhao unit[1].b_memory_type = 0x3; 2512c3d2faaSYifeng Zhao unit[1].d_num_alloc_units = (4 * 0x800 * cap_adj_fac + denominator - 1) / denominator; 2522c3d2faaSYifeng Zhao alloced_units += unit[1].d_num_alloc_units; 2532c3d2faaSYifeng Zhao /* lu 2: boot lu B 4MB */ 2542c3d2faaSYifeng Zhao unit[2].b_boot_lun_id = WELL_BOOT_LU_B; /* lu 1, boot b */ 2552c3d2faaSYifeng Zhao unit[2].b_memory_type = 0x3; /* lu 0, Enhanced Memory */ 2562c3d2faaSYifeng Zhao unit[2].d_num_alloc_units = (4 * 0x800 * cap_adj_fac + denominator - 1) / denominator; 2572c3d2faaSYifeng Zhao alloced_units += unit[2].d_num_alloc_units; 2582c3d2faaSYifeng Zhao /* lu 3: data lu 8MB */ 2592c3d2faaSYifeng Zhao unit[3].b_boot_lun_id = 0x0; /* lu 2 */ 2602c3d2faaSYifeng Zhao unit[3].b_memory_type = 0x3; /* lu 2, Enhanced Memory */ 2612c3d2faaSYifeng Zhao unit[3].d_num_alloc_units = (8 * 0x800 * cap_adj_fac + denominator - 1) / denominator; 2622c3d2faaSYifeng Zhao alloced_units += unit[3].d_num_alloc_units; 2631e6560dfSYifeng Zhao 264*1865a7e4SYifeng Zhao if (max_wb_alloc_units) { 265*1865a7e4SYifeng Zhao wb_alloc_units = max_wb_alloc_units; 266*1865a7e4SYifeng Zhao if (wb_alloc_units > max_wb_alloc_units) 267*1865a7e4SYifeng Zhao wb_alloc_units = max_wb_alloc_units; 268*1865a7e4SYifeng Zhao dev->b_write_booster_buffer_reserve_user_space_en = 1; 269*1865a7e4SYifeng Zhao dev->b_write_booster_buffer_type = 1; 270*1865a7e4SYifeng Zhao dev->d_num_shared_write_booster_buffer_alloc_units = to_bigendian32(wb_alloc_units); 271*1865a7e4SYifeng Zhao } 272*1865a7e4SYifeng Zhao 2732c3d2faaSYifeng Zhao /* lu 0: data lu, max capacity*/ 2742c3d2faaSYifeng Zhao unit[0].b_boot_lun_id = 0x0; /* lu 3 */ 2752c3d2faaSYifeng Zhao unit[0].b_memory_type = 0x0; /* lu 3, Normal Memory */ 2762c3d2faaSYifeng Zhao unit[0].d_num_alloc_units = lower_32_bits(total_raw_device_capacity) / denominator - alloced_units; 2772c3d2faaSYifeng Zhao 2782c3d2faaSYifeng Zhao for (i = 0; i <= 3; i++) { /* lu 0 - 3 */ 2792c3d2faaSYifeng Zhao unit[i].b_lu_enable = 0x1; 2802c3d2faaSYifeng Zhao unit[i].b_lu_write_protect = 0x0; 2812c3d2faaSYifeng Zhao unit[i].b_data_reliability = 0x1; 2822c3d2faaSYifeng Zhao unit[i].b_logical_block_size = 0x0c; 2832c3d2faaSYifeng Zhao unit[i].b_provisioning_type = 0x2; 2842c3d2faaSYifeng Zhao unit[i].w_context_capabilities = 0x0; 2852c3d2faaSYifeng Zhao unit[i].d_num_alloc_units = to_bigendian32(unit[i].d_num_alloc_units); 2862c3d2faaSYifeng Zhao } 2872c3d2faaSYifeng Zhao } 2882c3d2faaSYifeng Zhao 2892c3d2faaSYifeng Zhao static int compair_conf_desp(struct ufs_configuration_descriptor *cda, struct ufs_configuration_descriptor *cdb) 2902c3d2faaSYifeng Zhao { 2912c3d2faaSYifeng Zhao struct ufs_dev_desc_configuration_param *dev_a, *dev_b; 2922c3d2faaSYifeng Zhao struct ufs_unit_desc_configuration_param *unit_a, *unit_b; 2932c3d2faaSYifeng Zhao int i, ret; 2942c3d2faaSYifeng Zhao 2952c3d2faaSYifeng Zhao dev_a = &cda->dev_desc_conf_param; 2962c3d2faaSYifeng Zhao dev_b = &cdb->dev_desc_conf_param; 2972c3d2faaSYifeng Zhao 2982c3d2faaSYifeng Zhao if (dev_a->b_boot_enable != dev_b->b_boot_enable) 2992c3d2faaSYifeng Zhao return 0x3; 3002c3d2faaSYifeng Zhao if (dev_a->b_descr_access_en != dev_b->b_descr_access_en) 3012c3d2faaSYifeng Zhao return 0x4; 3022c3d2faaSYifeng Zhao if (dev_a->b_init_power_mode != dev_b->b_init_power_mode) 3032c3d2faaSYifeng Zhao return 0x5; 3042c3d2faaSYifeng Zhao if (dev_a->b_high_priority_lun != dev_b->b_high_priority_lun) 3052c3d2faaSYifeng Zhao return 0x6; 3062c3d2faaSYifeng Zhao if (dev_a->b_secure_removal_type != dev_b->b_secure_removal_type) 3072c3d2faaSYifeng Zhao return 0x7; 3082c3d2faaSYifeng Zhao if (dev_a->b_init_active_icc_level != dev_b->b_init_active_icc_level) 3092c3d2faaSYifeng Zhao return 0x8; 3102c3d2faaSYifeng Zhao if (dev_a->w_periodic_rtc_update != dev_b->w_periodic_rtc_update) 3112c3d2faaSYifeng Zhao return 0x9; 312*1865a7e4SYifeng Zhao if (dev_a->b_write_booster_buffer_reserve_user_space_en != 313*1865a7e4SYifeng Zhao dev_b->b_write_booster_buffer_reserve_user_space_en) 314*1865a7e4SYifeng Zhao return 0xA; 315*1865a7e4SYifeng Zhao if (dev_a->b_write_booster_buffer_type != dev_b->b_write_booster_buffer_type) 316*1865a7e4SYifeng Zhao return 0xB; 317*1865a7e4SYifeng Zhao if (dev_a->d_num_shared_write_booster_buffer_alloc_units != 318*1865a7e4SYifeng Zhao dev_b->d_num_shared_write_booster_buffer_alloc_units) 319*1865a7e4SYifeng Zhao return 0xC; 3202c3d2faaSYifeng Zhao 3212c3d2faaSYifeng Zhao for (i = 0; i < UNIT_DESCS_COUNT; i++) { 3222c3d2faaSYifeng Zhao unit_a = &cda->unit_desc_conf_param[i]; 3232c3d2faaSYifeng Zhao unit_b = &cdb->unit_desc_conf_param[i]; 3242c3d2faaSYifeng Zhao 3252c3d2faaSYifeng Zhao ret = 0x10 * (i + 1); 3262c3d2faaSYifeng Zhao if (unit_a->b_lu_enable != unit_b->b_lu_enable) 3272c3d2faaSYifeng Zhao return ret; 3282c3d2faaSYifeng Zhao if (unit_a->b_boot_lun_id != unit_b->b_boot_lun_id) 3292c3d2faaSYifeng Zhao return ret + 0x1; 3302c3d2faaSYifeng Zhao if (unit_a->b_lu_write_protect != unit_b->b_lu_write_protect) 3312c3d2faaSYifeng Zhao return ret + 0x2; 3322c3d2faaSYifeng Zhao if (unit_a->b_memory_type != unit_b->b_memory_type) 3332c3d2faaSYifeng Zhao return ret + 0x3; 3342c3d2faaSYifeng Zhao if (unit_a->d_num_alloc_units != unit_b->d_num_alloc_units) 3352c3d2faaSYifeng Zhao return ret + 0x4; 3362c3d2faaSYifeng Zhao if (unit_a->b_data_reliability != unit_b->b_data_reliability) 3372c3d2faaSYifeng Zhao return ret + 0x8; 3382c3d2faaSYifeng Zhao if (unit_a->b_logical_block_size != unit_b->b_logical_block_size) 3392c3d2faaSYifeng Zhao return ret + 0x9; 3402c3d2faaSYifeng Zhao if (unit_a->b_provisioning_type != unit_b->b_provisioning_type) 3412c3d2faaSYifeng Zhao return ret + 0xA; 3422c3d2faaSYifeng Zhao if (unit_a->w_context_capabilities != unit_b->w_context_capabilities) 3432c3d2faaSYifeng Zhao return ret + 0xB; 3442c3d2faaSYifeng Zhao } 3452c3d2faaSYifeng Zhao return 0; 3462c3d2faaSYifeng Zhao } 3472c3d2faaSYifeng Zhao 3482c3d2faaSYifeng Zhao 3491e6560dfSYifeng Zhao /** 3501e6560dfSYifeng Zhao * ufshcd_init_query() - init the query response and request parameters 3511e6560dfSYifeng Zhao */ 3521e6560dfSYifeng Zhao static inline void ufshcd_init_query(struct ufs_hba *hba, 3531e6560dfSYifeng Zhao struct ufs_query_req **request, 3541e6560dfSYifeng Zhao struct ufs_query_res **response, 3551e6560dfSYifeng Zhao enum query_opcode opcode, 3561e6560dfSYifeng Zhao u8 idn, u8 index, u8 selector) 3571e6560dfSYifeng Zhao { 3581e6560dfSYifeng Zhao *request = &hba->dev_cmd.query.request; 3591e6560dfSYifeng Zhao *response = &hba->dev_cmd.query.response; 3601e6560dfSYifeng Zhao memset(*request, 0, sizeof(struct ufs_query_req)); 3611e6560dfSYifeng Zhao memset(*response, 0, sizeof(struct ufs_query_res)); 3621e6560dfSYifeng Zhao (*request)->upiu_req.opcode = opcode; 3631e6560dfSYifeng Zhao (*request)->upiu_req.idn = idn; 3641e6560dfSYifeng Zhao (*request)->upiu_req.index = index; 3651e6560dfSYifeng Zhao (*request)->upiu_req.selector = selector; 3661e6560dfSYifeng Zhao } 3671e6560dfSYifeng Zhao 3681e6560dfSYifeng Zhao /** 3691e6560dfSYifeng Zhao * ufshcd_query_flag() - API function for sending flag query requests 3701e6560dfSYifeng Zhao */ 3711e6560dfSYifeng Zhao static int ufshcd_query_attribute(struct ufs_hba *hba,enum query_opcode opcode, 3721e6560dfSYifeng Zhao enum attr_id idn, u8 index, u8 selector, u32 *value) 3731e6560dfSYifeng Zhao { 3741e6560dfSYifeng Zhao struct ufs_query_req *request = &hba->dev_cmd.query.request; 3751e6560dfSYifeng Zhao struct ufs_query_res *response = &hba->dev_cmd.query.response; 3761e6560dfSYifeng Zhao int err; 3771e6560dfSYifeng Zhao int timeout = QUERY_REQ_TIMEOUT; 3781e6560dfSYifeng Zhao 3791e6560dfSYifeng Zhao memset(request, 0, sizeof(struct ufs_query_req)); 3801e6560dfSYifeng Zhao memset(response, 0, sizeof(struct ufs_query_res)); 3811e6560dfSYifeng Zhao request->upiu_req.opcode = opcode; 3821e6560dfSYifeng Zhao request->upiu_req.idn = idn; 3831e6560dfSYifeng Zhao request->upiu_req.index = 0; 3841e6560dfSYifeng Zhao request->upiu_req.selector = 0; 3851e6560dfSYifeng Zhao 3861e6560dfSYifeng Zhao switch (opcode) { 3871e6560dfSYifeng Zhao case UPIU_QUERY_OPCODE_WRITE_ATTR: 3881e6560dfSYifeng Zhao request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; 3891e6560dfSYifeng Zhao request->upiu_req.value = be32_to_cpu(*value); 3901e6560dfSYifeng Zhao break; 3911e6560dfSYifeng Zhao case UPIU_QUERY_OPCODE_READ_ATTR: 3921e6560dfSYifeng Zhao request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; 3931e6560dfSYifeng Zhao break; 3941e6560dfSYifeng Zhao default: 3951e6560dfSYifeng Zhao dev_err(hba->dev, 3961e6560dfSYifeng Zhao "%s: Expected query flag opcode but got = %d\n", 3971e6560dfSYifeng Zhao __func__, opcode); 3981e6560dfSYifeng Zhao err = -EINVAL; 3991e6560dfSYifeng Zhao goto out; 4001e6560dfSYifeng Zhao } 4011e6560dfSYifeng Zhao 4021e6560dfSYifeng Zhao err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout); 4031e6560dfSYifeng Zhao 4041e6560dfSYifeng Zhao if (err) { 4051e6560dfSYifeng Zhao dev_err(hba->dev, 4061e6560dfSYifeng Zhao "%s: Sending flag query for idn %d failed, err = %d\n", 4071e6560dfSYifeng Zhao __func__, idn, err); 4081e6560dfSYifeng Zhao goto out; 4091e6560dfSYifeng Zhao } 4101e6560dfSYifeng Zhao 4111e6560dfSYifeng Zhao if (value) 4121e6560dfSYifeng Zhao *value = be32_to_cpu(response->upiu_res.value); 4131e6560dfSYifeng Zhao 4141e6560dfSYifeng Zhao out: 4151e6560dfSYifeng Zhao return err; 4161e6560dfSYifeng Zhao } 4171e6560dfSYifeng Zhao 4181e6560dfSYifeng Zhao static int ufshcd_query_attribute_retry(struct ufs_hba *hba, enum query_opcode opcode, 4191e6560dfSYifeng Zhao enum attr_id idn, u8 index, u8 selector, u32 *value) 4201e6560dfSYifeng Zhao { 4211e6560dfSYifeng Zhao int ret; 4221e6560dfSYifeng Zhao int retries; 4231e6560dfSYifeng Zhao 4241e6560dfSYifeng Zhao for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) { 4251e6560dfSYifeng Zhao ret = ufshcd_query_attribute(hba, opcode, idn, index, selector, value); 4261e6560dfSYifeng Zhao if (ret) 4271e6560dfSYifeng Zhao dev_dbg(hba->dev, 4281e6560dfSYifeng Zhao "%s: failed with error %d, retries %d\n", 4291e6560dfSYifeng Zhao __func__, ret, retries); 4301e6560dfSYifeng Zhao else 4311e6560dfSYifeng Zhao break; 4321e6560dfSYifeng Zhao } 4331e6560dfSYifeng Zhao 4341e6560dfSYifeng Zhao if (ret) 4351e6560dfSYifeng Zhao dev_err(hba->dev, 4361e6560dfSYifeng Zhao "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n", 4371e6560dfSYifeng Zhao __func__, opcode, idn, ret, retries); 4382c3d2faaSYifeng Zhao return ret; 4392c3d2faaSYifeng Zhao } 4402c3d2faaSYifeng Zhao 4411e6560dfSYifeng Zhao static int read_attribute(struct ufs_hba *hba, enum attr_id idn, u8 index, u8 selector, u32 *value) 4422c3d2faaSYifeng Zhao { 4431e6560dfSYifeng Zhao int ret; 4442c3d2faaSYifeng Zhao 4451e6560dfSYifeng Zhao ret = ufshcd_query_attribute_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, 4461e6560dfSYifeng Zhao idn, index, 0, value); 4471e6560dfSYifeng Zhao return ret; 4481e6560dfSYifeng Zhao } 4491e6560dfSYifeng Zhao 4501e6560dfSYifeng Zhao static int write_attribute(struct ufs_hba *hba, enum attr_id idn, u8 index, u8 selector, u32 *value) 4511e6560dfSYifeng Zhao { 4521e6560dfSYifeng Zhao int ret; 4531e6560dfSYifeng Zhao 4541e6560dfSYifeng Zhao ret = ufshcd_query_attribute_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, 4551e6560dfSYifeng Zhao idn, index, 0, value); 4562c3d2faaSYifeng Zhao return ret; 4572c3d2faaSYifeng Zhao } 4582c3d2faaSYifeng Zhao 4592c3d2faaSYifeng Zhao static int set_boot_lu_enable(struct ufs_hba *hba) 4602c3d2faaSYifeng Zhao { 4612c3d2faaSYifeng Zhao uint32_t value = 0; 4622c3d2faaSYifeng Zhao uint32_t target_value = DEFAULT_BOOT_LUN; 4632c3d2faaSYifeng Zhao int ret; 4642c3d2faaSYifeng Zhao 4652c3d2faaSYifeng Zhao ret = read_attribute(hba, B_BOOT_LUNEN, 0, 0, &value); 4662c3d2faaSYifeng Zhao if (ret) { 4672c3d2faaSYifeng Zhao printf("read bBootLunEn fail. ret = %d\n", ret); 4682c3d2faaSYifeng Zhao return ret; 4692c3d2faaSYifeng Zhao } 4702c3d2faaSYifeng Zhao 4712c3d2faaSYifeng Zhao if (value != 0) 4721e6560dfSYifeng Zhao printf("UFS get boot W-LU-%c\n", (value == WELL_BOOT_LU_A) ? 'A' : 'B'); 4732c3d2faaSYifeng Zhao 4742c3d2faaSYifeng Zhao if (value == target_value) 4752c3d2faaSYifeng Zhao return 0; 4762c3d2faaSYifeng Zhao 4772c3d2faaSYifeng Zhao /* set default boot from Boot LU A */ 4782c3d2faaSYifeng Zhao value = target_value; 4792c3d2faaSYifeng Zhao ret = write_attribute(hba, B_BOOT_LUNEN, 0, 0, &value); 4802c3d2faaSYifeng Zhao if (ret) { 4812c3d2faaSYifeng Zhao printf("write bBootLunEn attribute fail. ret = %d\n", ret); 4822c3d2faaSYifeng Zhao return ret; 4832c3d2faaSYifeng Zhao } 4842c3d2faaSYifeng Zhao 4851e6560dfSYifeng Zhao ret = read_attribute(hba, B_BOOT_LUNEN, 0, 0, &value); 4861e6560dfSYifeng Zhao if (ret) { 4871e6560dfSYifeng Zhao printf("read bBootLunEn fail. ret = %d\n", ret); 4882c3d2faaSYifeng Zhao return ret; 4892c3d2faaSYifeng Zhao } 4902c3d2faaSYifeng Zhao 4911e6560dfSYifeng Zhao if (target_value == value) 4921e6560dfSYifeng Zhao return 0; 4931e6560dfSYifeng Zhao 4941e6560dfSYifeng Zhao printf("UFS set boot W-LU(%c) Fail value = %x\n", (value == WELL_BOOT_LU_A) ? 'A' : 'B', value); 4951e6560dfSYifeng Zhao return 0; 4961e6560dfSYifeng Zhao } 4971e6560dfSYifeng Zhao 4981e6560dfSYifeng Zhao static int ufs_set_ref_clk(struct ufs_hba *hba) 4991e6560dfSYifeng Zhao { 5001e6560dfSYifeng Zhao uint32_t value; 5011e6560dfSYifeng Zhao int ret; 5021e6560dfSYifeng Zhao uint32_t target_ref_clk; 5031e6560dfSYifeng Zhao 5041e6560dfSYifeng Zhao target_ref_clk = 1; /* 26 MHz */ 5051e6560dfSYifeng Zhao 5061e6560dfSYifeng Zhao ret = read_attribute(hba, B_REFCLK_FREQ, 0, 0, &value); 5071e6560dfSYifeng Zhao if (ret) { 5081e6560dfSYifeng Zhao printf("read bRefClkFreq fail. ret = %d\n", ret); 5091e6560dfSYifeng Zhao return ret; 5101e6560dfSYifeng Zhao } 5111e6560dfSYifeng Zhao 5121e6560dfSYifeng Zhao printf("UFS get ref clock %d Mhz\n", (value == 1) ? 26 : 19); 5131e6560dfSYifeng Zhao if (target_ref_clk == value) 5141e6560dfSYifeng Zhao return 0; 5151e6560dfSYifeng Zhao 5161e6560dfSYifeng Zhao /* set default boot from Boot LU A */ 5171e6560dfSYifeng Zhao ret = write_attribute(hba, B_REFCLK_FREQ, 0, 0, &target_ref_clk); 5181e6560dfSYifeng Zhao if (ret) { 5191e6560dfSYifeng Zhao printf("write bRefClkFreq attribute fail. ret = %d\n", ret); 5201e6560dfSYifeng Zhao return ret; 5211e6560dfSYifeng Zhao } 5221e6560dfSYifeng Zhao 5231e6560dfSYifeng Zhao ret = read_attribute(hba, B_REFCLK_FREQ, 0, 0, &value); 5241e6560dfSYifeng Zhao if (ret) { 5251e6560dfSYifeng Zhao printf("read bRefClkFreq fail. ret = %d\n", ret); 5261e6560dfSYifeng Zhao return ret; 5271e6560dfSYifeng Zhao } 5281e6560dfSYifeng Zhao 5291e6560dfSYifeng Zhao if (target_ref_clk == value) 5301e6560dfSYifeng Zhao return 0; 5311e6560dfSYifeng Zhao 5321e6560dfSYifeng Zhao printf("UFS set bRefClkFreq 26Mhz Fail\n"); 5331e6560dfSYifeng Zhao return -EINVAL; 5341e6560dfSYifeng Zhao } 5351e6560dfSYifeng Zhao 5362c3d2faaSYifeng Zhao int ufs_create_partition_inventory(struct ufs_hba *hba) 5372c3d2faaSYifeng Zhao { 5382c3d2faaSYifeng Zhao int err, length; 5392c3d2faaSYifeng Zhao 5402c3d2faaSYifeng Zhao length = (int)sizeof(struct ufs_geometry_descriptor); 5412c3d2faaSYifeng Zhao if (length > hba->desc_size.geom_desc) 5422c3d2faaSYifeng Zhao length = hba->desc_size.geom_desc; 5432c3d2faaSYifeng Zhao err = ufshcd_read_desc_param(hba, QUERY_DESC_IDN_GEOMETRY, 0, 0, (u8 *)hba->geo_desc, length); 5442c3d2faaSYifeng Zhao if (err) { 5452c3d2faaSYifeng Zhao dev_err(hba->dev, "%s: Failed reading geometry Desc. err = %d\n", __func__, err); 5462c3d2faaSYifeng Zhao return err; 5472c3d2faaSYifeng Zhao } 5482c3d2faaSYifeng Zhao 549*1865a7e4SYifeng Zhao dev_err(hba->dev, "%s: WB_max_alloc_units = %x\n", __func__, 550*1865a7e4SYifeng Zhao hba->geo_desc->d_write_booster_buffer_max_alloc_units); 551*1865a7e4SYifeng Zhao 5522c3d2faaSYifeng Zhao err = ufs_get_configuration_desc(hba, hba->rc_desc); 5532c3d2faaSYifeng Zhao if (err) { 5542c3d2faaSYifeng Zhao dev_err(hba->dev, "%s: Failed getting conf info. err = %d\n", __func__, err); 5552c3d2faaSYifeng Zhao return err; 5562c3d2faaSYifeng Zhao } 5572c3d2faaSYifeng Zhao ufs_info_show_conf_desc(hba->rc_desc); 5582c3d2faaSYifeng Zhao 5592c3d2faaSYifeng Zhao memset(hba->wc_desc, 0, sizeof(struct ufs_configuration_descriptor)); 5602c3d2faaSYifeng Zhao hba->wc_desc->dev_desc_conf_param.b_length = hba->rc_desc->dev_desc_conf_param.b_length; 5612c3d2faaSYifeng Zhao hba->wc_desc->dev_desc_conf_param.b_descriptor_idn = hba->rc_desc->dev_desc_conf_param.b_descriptor_idn; 5622c3d2faaSYifeng Zhao ufs_lu_configuration(hba, hba->wc_desc); 5632c3d2faaSYifeng Zhao ufs_info_show_conf_desc(hba->wc_desc); 5642c3d2faaSYifeng Zhao 5652c3d2faaSYifeng Zhao err = compair_conf_desp(hba->wc_desc, hba->rc_desc); 5662c3d2faaSYifeng Zhao printf("compair_conf_desp: 0x%x\n", err); 5672c3d2faaSYifeng Zhao 5682c3d2faaSYifeng Zhao if (!err) 5691e6560dfSYifeng Zhao goto out; 5702c3d2faaSYifeng Zhao 5712c3d2faaSYifeng Zhao err = ufs_write_configuration_desc(hba, hba->wc_desc); 5722c3d2faaSYifeng Zhao if (err) 5732c3d2faaSYifeng Zhao dev_err(hba->dev, "%s: Failed write conf info. err = %d\n", __func__, err); 5742c3d2faaSYifeng Zhao 5752c3d2faaSYifeng Zhao err = _ufs_start(hba); 5762c3d2faaSYifeng Zhao if (err) 5772c3d2faaSYifeng Zhao return err; 5781e6560dfSYifeng Zhao out: 5792c3d2faaSYifeng Zhao ufs_info_show_dev_desc(hba->dev_desc); 5802c3d2faaSYifeng Zhao 5811e6560dfSYifeng Zhao ufs_set_ref_clk(hba); 5821e6560dfSYifeng Zhao 5832c3d2faaSYifeng Zhao return set_boot_lu_enable(hba); 5842c3d2faaSYifeng Zhao } 5852c3d2faaSYifeng Zhao #endif 586