Hi Jeffrey,

On Mon, May 23, 2016 at 10:43:53PM +0800, jeffrey.lin wrote:
> Hi Dmitry:
> 
> >static int raydium_i2c_read_message(struct i2c_client *client,
> >                                 u32 addr, void *data, size_t len)
> >{
> >     __le32 le_addr;
> >     size_t xfer_len;
> >     u32 shift_addr;
> >     int error;
> >
> >     while (len) {
> >             xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE);
> >
> >             le_addr = cpu_to_le32(addr);
> >
> >             shift_addr = le_addr >> 8;/*send the first 3rd byte addr.*/
> Drop this. Change touch MCU setting to solve this issue
> >             error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
> >                                      &shift_addr, sizeof(le_addr));
> >             if (!error)/*read from last byte addr.*/
> >                     error = raydium_i2c_read(client, le_addr & 0xff,
> >                                              data, xfer_len);
> >             if (error)
> >                     return error;
> >
> >             len -= xfer_len;
> >             data += xfer_len;
> >             addr += xfer_len;
> >     }
> >
> >     return 0;
> >}
> modify as below.
> 
> static int raydium_i2c_read_message(struct i2c_client *client,
>                                   u32 addr, void *data, size_t len)
> {
>       __le32 le_addr;
>       size_t xfer_len;
>       int error;
> 
>       while (len) {
>               xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE);
> 
>               le_addr = cpu_to_le32(addr);
> 
>               error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
>                                        &le_addr, sizeof(le_addr));
>               if (!error)/*read from last byte addr.*/
>                       error = raydium_i2c_read(client, le_addr & 0xff,
>                                                data, xfer_len);

No, not "le_addr & 0xff", "addr & 0xff"! When you do calculations, you
have to do it using values in CPU endianness, not fixed endianness (BE
or LE) so that the code will work on all architectures.

>               if (error)
>                       return error;
> 
>               len -= xfer_len;
>               data += xfer_len;
>               addr += xfer_len;
>       }
> 
>       return 0;
> }
> 
> >
> >>> static int raydium_i2c_fw_write_page(struct i2c_client *client,
> >>>                                u16 page_idx, const void *data, size_t len)
> >>> {
> >>>   u8 buf[RM_BL_WRT_LEN];
> >>>   u8 pkg_idx = 1;
> >>>   size_t xfer_len;
> >>>   int error;
> >>> 
> >>>   while (len) {
> >>>           xfer_len = min_t(size_t, len, RM_BL_WRT_PKG_SIZE);
> >>>           buf[BL_HEADER] = RM_CMD_BOOT_PAGE_WRT;
> >>>           /*FIXME,Touch MCU need zero index as start page*/
> >>>           buf[BL_PAGE_STR] = page_idx ? 0xff : 0;
> >>>           buf[BL_PKG_IDX] = pkg_idx++;
> >>> 
> >>>           memcpy(&buf[BL_DATA_STR], data, xfer_len);
> >>> 
> >>>           if (len < RM_BL_WRT_PKG_SIZE) {
> >>>                   buf[BL_PKG_IDX] = 4;
> Drop this one. Modfy boot loader firmware to meet this issue. So final 
> function as below.
> static int raydium_i2c_fw_write_page(struct i2c_client *client,
>                                    u16 page_idx, const void *data, size_t len)
> {
>       u8 buf[RM_BL_WRT_LEN];
>       u8 pkg_idx = 1;
>       size_t xfer_len;
>       int error;
> 
>       while (len) {
>               xfer_len = min_t(size_t, len, RM_BL_WRT_PKG_SIZE);
>               buf[BL_HEADER] = RM_CMD_BOOT_PAGE_WRT;
>               /*FIXME,Touch MCU need zero index as start page*/
>               buf[BL_PAGE_STR] = page_idx ? 0xff : 0;
>               buf[BL_PKG_IDX] = pkg_idx++;
> 
>               memcpy(&buf[BL_DATA_STR], data, xfer_len);
> 
>               if (len < RM_BL_WRT_PKG_SIZE) {
>                       memset(buf + BL_DATA_STR + xfer_len, 0xff,
>                               RM_BL_WRT_PKG_SIZE - xfer_len);
>               }
> 
>               error = raydium_i2c_write_object(client, buf, RM_BL_WRT_LEN,
>                                                RAYDIUM_WAIT_READY);
>               if (error) {
>                       dev_err(&client->dev,
>                               "page write command failed for page %d, chunk 
> %d: %d\n",
>                               page_idx, pkg_idx, error);
>                       return error;
>               }
>               data += xfer_len;
>               len -= xfer_len;
>       }
> 
>       return error;
> }

What will be the trigger for the flash? If you really need full page,
then you want to :

        BUILD_BUG_ON((RM_FW_PAGE_SIZE % RM_BL_WRT_PKG_SIZE) != 0);

        for (i = 0; i < RM_FW_PAGE_SIZE / RM_BL_WRT_PKG_SIZE; i++) {
                buf[BL_HEADER] = RM_CMD_BOOT_PAGE_WRT;
                buf[BL_PAGE_STR] = i ? 0xff : 0;
                buf[BL_PKG_IDX] = i;

                xfer_len = min_t(size_t, len, RM_BL_WRT_PKG_SIZE);
                memcpy(&buf[BL_DATA_STR], data, xfer_len);
                if (len < RM_BL_WRT_PKG_SIZE)
                        memset(&buf[BL_DATA_STR + xfer_len], 0xff,
                                RM_BL_WRT_PKG_SIZE - xfer_len);

                error = raydium_i2c_write_object(client, buf, RM_BL_WRT_LEN,
                                                 RAYDIUM_WAIT_READY);
                if (error) {
                        dev_err(&client->dev,
                                "page write command failed for page %d, chunk 
%d: %d\n",
                                page_idx, pkg_idx, error);
                        return error;
                }

                data += xfer_len;
                len -= xfer_len;
        }

The BUILD_BUG_ON is because I do not want to handle the case where last
chunk would cross over the page boundary so we'd have to cut it short.
It simply is not worth it.

Thanks.

-- 
Dmitry

Reply via email to