root/drivers/staging/rtl8188eu/hal/fw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _rtl88e_enable_fw_download
  2. _rtl88e_fw_block_write
  3. _rtl88e_fw_page_write
  4. _rtl88e_write_fw
  5. rtl88e_firmware_selfreset
  6. _rtl88e_fw_free_to_go
  7. rtl88eu_download_fw

   1 // SPDX-License-Identifier: GPL-2.0
   2 /******************************************************************************
   3  *
   4  * Copyright(c) 2009-2013  Realtek Corporation.
   5  *
   6  * Contact Information:
   7  * wlanfae <wlanfae@realtek.com>
   8  * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
   9  * Hsinchu 300, Taiwan.
  10  *
  11  * Larry Finger <Larry.Finger@lwfinger.net>
  12  *
  13  *****************************************************************************/
  14 
  15 #include "fw.h"
  16 #include "drv_types.h"
  17 #include "usb_ops_linux.h"
  18 #include "rtl8188e_spec.h"
  19 #include "rtl8188e_hal.h"
  20 
  21 #include <linux/firmware.h>
  22 #include <linux/slab.h>
  23 
  24 static void _rtl88e_enable_fw_download(struct adapter *adapt, bool enable)
  25 {
  26         u8 tmp;
  27 
  28         if (enable) {
  29                 tmp = usb_read8(adapt, REG_MCUFWDL);
  30                 usb_write8(adapt, REG_MCUFWDL, tmp | 0x01);
  31 
  32                 tmp = usb_read8(adapt, REG_MCUFWDL + 2);
  33                 usb_write8(adapt, REG_MCUFWDL + 2, tmp & 0xf7);
  34         } else {
  35                 tmp = usb_read8(adapt, REG_MCUFWDL);
  36                 usb_write8(adapt, REG_MCUFWDL, tmp & 0xfe);
  37 
  38                 usb_write8(adapt, REG_MCUFWDL + 1, 0x00);
  39         }
  40 }
  41 
  42 static void _rtl88e_fw_block_write(struct adapter *adapt,
  43                                    const u8 *buffer, u32 size)
  44 {
  45         u32 blk_sz = sizeof(u32);
  46         const u8 *byte_buffer;
  47         const u32 *dword_buffer = (u32 *)buffer;
  48         u32 i, write_address, blk_cnt, remain;
  49 
  50         blk_cnt = size / blk_sz;
  51         remain = size % blk_sz;
  52 
  53         write_address = FW_8192C_START_ADDRESS;
  54 
  55         for (i = 0; i < blk_cnt; i++, write_address += blk_sz)
  56                 usb_write32(adapt, write_address, dword_buffer[i]);
  57 
  58         byte_buffer = buffer + blk_cnt * blk_sz;
  59         for (i = 0; i < remain; i++, write_address++)
  60                 usb_write8(adapt, write_address, byte_buffer[i]);
  61 }
  62 
  63 static void _rtl88e_fw_page_write(struct adapter *adapt,
  64                                   u32 page, const u8 *buffer, u32 size)
  65 {
  66         u8 value8;
  67         u8 u8page = (u8)(page & 0x07);
  68 
  69         value8 = (usb_read8(adapt, REG_MCUFWDL + 2) & 0xF8) | u8page;
  70 
  71         usb_write8(adapt, (REG_MCUFWDL + 2), value8);
  72         _rtl88e_fw_block_write(adapt, buffer, size);
  73 }
  74 
  75 static void _rtl88e_write_fw(struct adapter *adapt, u8 *buffer, u32 size)
  76 {
  77         u8 *buf_ptr = buffer;
  78         u32 page_no, remain;
  79         u32 page, offset;
  80 
  81         page_no = size / FW_8192C_PAGE_SIZE;
  82         remain = size % FW_8192C_PAGE_SIZE;
  83 
  84         for (page = 0; page < page_no; page++) {
  85                 offset = page * FW_8192C_PAGE_SIZE;
  86                 _rtl88e_fw_page_write(adapt, page, (buf_ptr + offset),
  87                                       FW_8192C_PAGE_SIZE);
  88         }
  89 
  90         if (remain) {
  91                 offset = page_no * FW_8192C_PAGE_SIZE;
  92                 page = page_no;
  93                 _rtl88e_fw_page_write(adapt, page, (buf_ptr + offset), remain);
  94         }
  95 }
  96 
  97 static void rtl88e_firmware_selfreset(struct adapter *adapt)
  98 {
  99         u8 u1b_tmp;
 100 
 101         u1b_tmp = usb_read8(adapt, REG_SYS_FUNC_EN + 1);
 102         usb_write8(adapt, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
 103         usb_write8(adapt, REG_SYS_FUNC_EN + 1, (u1b_tmp | BIT(2)));
 104 }
 105 
 106 static int _rtl88e_fw_free_to_go(struct adapter *adapt)
 107 {
 108         int err = -EIO;
 109         u32 counter = 0;
 110         u32 value32;
 111 
 112         do {
 113                 value32 = usb_read32(adapt, REG_MCUFWDL);
 114                 if (value32 & FWDL_ChkSum_rpt)
 115                         break;
 116         } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
 117 
 118         if (counter >= POLLING_READY_TIMEOUT_COUNT)
 119                 goto exit;
 120 
 121         value32 = usb_read32(adapt, REG_MCUFWDL);
 122         value32 |= MCUFWDL_RDY;
 123         value32 &= ~WINTINI_RDY;
 124         usb_write32(adapt, REG_MCUFWDL, value32);
 125 
 126         rtl88e_firmware_selfreset(adapt);
 127         counter = 0;
 128 
 129         do {
 130                 value32 = usb_read32(adapt, REG_MCUFWDL);
 131                 if (value32 & WINTINI_RDY) {
 132                         err = 0;
 133                         goto exit;
 134                 }
 135 
 136                 udelay(FW_8192C_POLLING_DELAY);
 137 
 138         } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
 139 
 140 exit:
 141         return err;
 142 }
 143 
 144 int rtl88eu_download_fw(struct adapter *adapt)
 145 {
 146         struct dvobj_priv *dvobj = adapter_to_dvobj(adapt);
 147         struct device *device = dvobj_to_dev(dvobj);
 148         const struct firmware *fw;
 149         const char fw_name[] = "rtlwifi/rtl8188eufw.bin";
 150         struct rtl92c_firmware_header *pfwheader = NULL;
 151         u8 *download_data, *fw_data;
 152         size_t download_size;
 153         unsigned int trailing_zeros_length;
 154 
 155         if (request_firmware(&fw, fw_name, device)) {
 156                 dev_err(device, "Firmware %s not available\n", fw_name);
 157                 return -ENOENT;
 158         }
 159 
 160         if (fw->size > FW_8188E_SIZE) {
 161                 dev_err(device, "Firmware size exceed 0x%X. Check it.\n",
 162                         FW_8188E_SIZE);
 163                 release_firmware(fw);
 164                 return -1;
 165         }
 166 
 167         trailing_zeros_length = (4 - fw->size % 4) % 4;
 168 
 169         fw_data = kmalloc(fw->size + trailing_zeros_length, GFP_KERNEL);
 170         if (!fw_data) {
 171                 release_firmware(fw);
 172                 return -ENOMEM;
 173         }
 174 
 175         memcpy(fw_data, fw->data, fw->size);
 176         memset(fw_data + fw->size, 0, trailing_zeros_length);
 177 
 178         pfwheader = (struct rtl92c_firmware_header *)fw_data;
 179 
 180         if (IS_FW_HEADER_EXIST(pfwheader)) {
 181                 download_data = fw_data + 32;
 182                 download_size = fw->size + trailing_zeros_length - 32;
 183         } else {
 184                 download_data = fw_data;
 185                 download_size = fw->size + trailing_zeros_length;
 186         }
 187 
 188         release_firmware(fw);
 189 
 190         if (usb_read8(adapt, REG_MCUFWDL) & RAM_DL_SEL) {
 191                 usb_write8(adapt, REG_MCUFWDL, 0);
 192                 rtl88e_firmware_selfreset(adapt);
 193         }
 194         _rtl88e_enable_fw_download(adapt, true);
 195         usb_write8(adapt, REG_MCUFWDL, usb_read8(adapt, REG_MCUFWDL) | FWDL_ChkSum_rpt);
 196         _rtl88e_write_fw(adapt, download_data, download_size);
 197         _rtl88e_enable_fw_download(adapt, false);
 198 
 199         kfree(fw_data);
 200         return _rtl88e_fw_free_to_go(adapt);
 201 }

/* [<][>][^][v][top][bottom][index][help] */