+ double CLK_OUT;
+
+ CLK_OUT = mg_do_calc_pll(XIN, p_pll_val, 0);
+
+ if (!CLK_OUT)
+ return mg_do_calc_pll(XIN, p_pll_val, 1);
+ else
+ return CLK_OUT;
+}
+
+static int mg_verify_interface(void)
+{
+ uint16_t buff[MG_MFLASH_SECTOR_SIZE >> 1];
+ uint16_t i, j;
+ uint32_t address = mflash_bank->base + MG_BUFFER_OFFSET;
+ struct target *target = mflash_bank->target;
+ int ret;
+
+ for (j = 0; j < 10; j++) {
+ for (i = 0; i < MG_MFLASH_SECTOR_SIZE >> 1; i++)
+ buff[i] = i;
+
+ ret = target_write_memory(target, address, 2,
+ MG_MFLASH_SECTOR_SIZE / 2, (uint8_t *)buff);
+ if (ret != ERROR_OK)
+ return ret;
+
+ memset(buff, 0xff, MG_MFLASH_SECTOR_SIZE);
+
+ ret = target_read_memory(target, address, 2,
+ MG_MFLASH_SECTOR_SIZE / 2, (uint8_t *)buff);
+ if (ret != ERROR_OK)
+ return ret;
+
+ for (i = 0; i < MG_MFLASH_SECTOR_SIZE >> 1; i++) {
+ if (buff[i] != i) {
+ LOG_ERROR("mflash: verify interface fail");
+ return ERROR_MG_INTERFACE;
+ }
+ }
+ }
+
+ LOG_INFO("mflash: verify interface ok");
+ return ret;
+}
+
+static const char g_strSEG_SerialNum[20] = {
+ 'G', 'm', 'n', 'i', '-', 'e', 'e', 'S', 'g', 'a', 'e', 'l',
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
+};
+
+static const char g_strSEG_FWRev[8] = {
+ 'F', 'X', 'L', 'T', '2', 'v', '0', '.'
+};
+
+static const char g_strSEG_ModelNum[40] = {
+ 'F', 'X', 'A', 'L', 'H', 'S', '2', 0x20, '0', '0', 's', '7',
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
+};
+
+static void mg_gen_ataid(mg_io_type_drv_info *pSegIdDrvInfo)
+{
+ /* b15 is ATA device(0) , b7 is Removable Media Device */
+ pSegIdDrvInfo->general_configuration = 0x045A;
+ /* 128MB : Cylinder=> 977 , Heads=> 8 , Sectors=> 32
+ * 256MB : Cylinder=> 980 , Heads=> 16 , Sectors=> 32
+ * 384MB : Cylinder=> 745 , Heads=> 16 , Sectors=> 63
+ */
+ pSegIdDrvInfo->number_of_cylinders = 0x02E9;
+ pSegIdDrvInfo->reserved1 = 0x0;
+ pSegIdDrvInfo->number_of_heads = 0x10;
+ pSegIdDrvInfo->unformatted_bytes_per_track = 0x0;
+ pSegIdDrvInfo->unformatted_bytes_per_sector = 0x0;
+ pSegIdDrvInfo->sectors_per_track = 0x3F;
+ pSegIdDrvInfo->vendor_unique1[0] = 0x000B;
+ pSegIdDrvInfo->vendor_unique1[1] = 0x7570;
+ pSegIdDrvInfo->vendor_unique1[2] = 0x8888;
+
+ memcpy(pSegIdDrvInfo->serial_number, g_strSEG_SerialNum, 20);
+ /* 0x2 : dual buffer */
+ pSegIdDrvInfo->buffer_type = 0x2;
+ /* buffer size : 2KB */
+ pSegIdDrvInfo->buffer_sector_size = 0x800;
+ pSegIdDrvInfo->number_of_ecc_bytes = 0;
+
+ memcpy(pSegIdDrvInfo->firmware_revision, g_strSEG_FWRev, 8);
+
+ memcpy(pSegIdDrvInfo->model_number, g_strSEG_ModelNum, 40);
+
+ pSegIdDrvInfo->maximum_block_transfer = 0x4;
+ pSegIdDrvInfo->vendor_unique2 = 0x0;
+ pSegIdDrvInfo->dword_io = 0x00;
+ /* b11 : IORDY support(PIO Mode 4), b10 : Disable/Enbale IORDY
+ * b9 : LBA support, b8 : DMA mode support
+ */
+ pSegIdDrvInfo->capabilities = 0x1 << 9;
+
+ pSegIdDrvInfo->reserved2 = 0x4000;
+ pSegIdDrvInfo->vendor_unique3 = 0x00;
+ /* PIOMode-2 support */
+ pSegIdDrvInfo->pio_cycle_timing_mode = 0x02;
+ pSegIdDrvInfo->vendor_unique4 = 0x00;
+ /* MultiWord-2 support */
+ pSegIdDrvInfo->dma_cycle_timing_mode = 0x00;
+ /* b1 : word64~70 is valid
+ * b0 : word54~58 are valid and reflect the current numofcyls,heads,sectors
+ * b2 : If device supports Ultra DMA , set to one to vaildate word88
+ */
+ pSegIdDrvInfo->translation_fields_valid = (0x1 << 1) | (0x1 << 0);
+ pSegIdDrvInfo->number_of_current_cylinders = 0x02E9;
+ pSegIdDrvInfo->number_of_current_heads = 0x10;
+ pSegIdDrvInfo->current_sectors_per_track = 0x3F;
+ pSegIdDrvInfo->current_sector_capacity_lo = 0x7570;
+ pSegIdDrvInfo->current_sector_capacity_hi = 0x000B;
+
+ pSegIdDrvInfo->multi_sector_count = 0x04;
+ /* b8 : Multiple secotr setting valid , b[7:0] num of secotrs per block */
+ pSegIdDrvInfo->multi_sector_setting_valid = 0x01;
+ pSegIdDrvInfo->total_user_addressable_sectors_lo = 0x7570;
+ pSegIdDrvInfo->total_user_addressable_sectors_hi = 0x000B;
+ pSegIdDrvInfo->single_dma_modes_supported = 0x00;
+ pSegIdDrvInfo->single_dma_transfer_active = 0x00;
+ /* b2 :Multi-word DMA mode 2, b1 : Multi-word DMA mode 1 */
+ pSegIdDrvInfo->multi_dma_modes_supported = (0x1 << 0);
+ /* b2 :Multi-word DMA mode 2, b1 : Multi-word DMA mode 1 */
+ pSegIdDrvInfo->multi_dma_transfer_active = (0x1 << 0);
+ /* b0 : PIO Mode-3 support, b1 : PIO Mode-4 support */
+ pSegIdDrvInfo->adv_pio_mode = 0x00;
+ /* 480(0x1E0)nsec for Multi-word DMA mode0
+ * 150(0x96) nsec for Multi-word DMA mode1
+ * 120(0x78) nsec for Multi-word DMA mode2
+ */
+ pSegIdDrvInfo->min_dma_cyc = 0x1E0;
+ pSegIdDrvInfo->recommend_dma_cyc = 0x1E0;
+ pSegIdDrvInfo->min_pio_cyc_no_iordy = 0x1E0;
+ pSegIdDrvInfo->min_pio_cyc_with_iordy = 0x1E0;
+ memset(pSegIdDrvInfo->reserved3, 0x00, 22);
+ /* b7 : ATA/ATAPI-7 ,b6 : ATA/ATAPI-6 ,b5 : ATA/ATAPI-5,b4 : ATA/ATAPI-4 */
+ pSegIdDrvInfo->major_ver_num = 0x7E;
+ /* 0x1C : ATA/ATAPI-6 T13 1532D revision1 */
+ pSegIdDrvInfo->minor_ver_num = 0x19;
+ /* NOP/READ BUFFER/WRITE BUFFER/Power management feature set support */
+ pSegIdDrvInfo->feature_cmd_set_suprt0 = 0x7068;
+ /* Features/command set is valid/Advanced Pwr management/CFA feature set
+ * not support
+ */
+ pSegIdDrvInfo->feature_cmd_set_suprt1 = 0x400C;
+ pSegIdDrvInfo->feature_cmd_set_suprt2 = 0x4000;
+ /* READ/WRITE BUFFER/PWR Management enable */
+ pSegIdDrvInfo->feature_cmd_set_en0 = 0x7000;
+ /* CFA feature is disabled / Advancde power management disable */
+ pSegIdDrvInfo->feature_cmd_set_en1 = 0x0;
+ pSegIdDrvInfo->feature_cmd_set_en2 = 0x4000;
+ pSegIdDrvInfo->reserved4 = 0x0;
+ /* 0x1 * 2minutes */
+ pSegIdDrvInfo->req_time_for_security_er_done = 0x19;
+ pSegIdDrvInfo->req_time_for_enhan_security_er_done = 0x19;
+ /* Advanced power management level 1 */
+ pSegIdDrvInfo->adv_pwr_mgm_lvl_val = 0x0;
+ pSegIdDrvInfo->reserved5 = 0x0;
+ memset(pSegIdDrvInfo->reserved6, 0x00, 68);
+ /* Security mode feature is disabled */
+ pSegIdDrvInfo->security_stas = 0x0;
+ memset(pSegIdDrvInfo->vendor_uniq_bytes, 0x00, 62);
+ /* CFA power mode 1 support in maximum 200mA */
+ pSegIdDrvInfo->cfa_pwr_mode = 0x0100;
+ memset(pSegIdDrvInfo->reserved7, 0x00, 190);
+}
+
+static int mg_storage_config(void)
+{
+ uint8_t buff[512];
+ int ret;
+
+ ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd);
+ if (ret != ERROR_OK)
+ return ret;
+
+ mg_gen_ataid((mg_io_type_drv_info *)(void *)buff);
+
+ ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_stgdrvinfo);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default);
+ if (ret != ERROR_OK)
+ return ret;
+
+ LOG_INFO("mflash: storage config ok");
+ return ret;
+}
+
+static int mg_boot_config(void)
+{
+ uint8_t buff[512];
+ int ret;
+
+ ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd);
+ if (ret != ERROR_OK)
+ return ret;
+
+ memset(buff, 0xff, 512);
+
+ buff[0] = mg_op_mode_snd; /* operation mode */
+ buff[1] = MG_UNLOCK_OTP_AREA;
+ buff[2] = 4; /* boot size */
+ *((uint32_t *)(void *)(buff + 4)) = 0; /* XIP size */
+
+ ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_update_xipinfo);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default);
+ if (ret != ERROR_OK)
+ return ret;
+
+ LOG_INFO("mflash: boot config ok");
+ return ret;
+}
+
+static int mg_set_pll(mg_pll_t *pll)
+{
+ uint8_t buff[512];
+ int ret;
+
+ memset(buff, 0xff, 512);
+ /* PLL Lock cycle and Feedback 9bit Divider */
+ memcpy(buff, &pll->lock_cyc, sizeof(uint32_t));
+ memcpy(buff + 4, &pll->feedback_div, sizeof(uint16_t));
+ buff[6] = pll->input_div; /* PLL Input 5bit Divider */
+ buff[7] = pll->output_div; /* PLL Output Divider */
+
+ ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = mg_mflash_do_write_sects(buff, 0, 1, mg_vcmd_wr_pll);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default);
+ if (ret != ERROR_OK)
+ return ret;
+
+ LOG_INFO("mflash: set pll ok");
+ return ret;
+}
+
+static int mg_erase_nand(void)
+{
+ int ret;
+
+ ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_vcmd);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = mg_mflash_do_write_sects(NULL, 0, 0, mg_vcmd_purge_nand);
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = mg_set_feature(mg_feature_id_transmode, mg_feature_val_trans_default);
+ if (ret != ERROR_OK)
+ return ret;
+
+ LOG_INFO("mflash: erase nand ok");
+ return ret;
+}
+
+COMMAND_HANDLER(mg_config_cmd)
+{
+ double fin, fout;
+ mg_pll_t pll;
+ int ret;
+
+ ret = mg_verify_interface();
+ if (ret != ERROR_OK)
+ return ret;
+
+ ret = mg_mflash_rst();
+ if (ret != ERROR_OK)
+ return ret;
+
+ switch (CMD_ARGC) {
+ case 2:
+ if (!strcmp(CMD_ARGV[1], "boot"))
+ return mg_boot_config();
+ else if (!strcmp(CMD_ARGV[1], "storage"))
+ return mg_storage_config();
+ else
+ return ERROR_COMMAND_NOTFOUND;
+ break;
+ case 3:
+ if (!strcmp(CMD_ARGV[1], "pll")) {
+ unsigned long freq;
+ COMMAND_PARSE_NUMBER(ulong, CMD_ARGV[2], freq);
+ fin = freq;
+
+ if (fin > MG_PLL_CLK_OUT) {
+ LOG_ERROR("mflash: input freq. is too large");
+ return ERROR_MG_INVALID_OSC;
+ }
+
+ fout = mg_calc_pll(fin, &pll);
+
+ if (!fout) {
+ LOG_ERROR("mflash: cannot generate valid pll");
+ return ERROR_MG_INVALID_PLL;
+ }