Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7111495 authored by Kalle Valo's avatar Kalle Valo
Browse files

ath6kl: move diag commands to hif driver



This is preparation for USB support which will have different diag
commands.

Based on code by Kevin Fang.

Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 1f4c894d
Loading
Loading
Loading
Loading
+20 −0
Original line number Original line Diff line number Diff line
@@ -91,6 +91,26 @@ static inline int ath6kl_hif_suspend(struct ath6kl *ar,
	return ar->hif_ops->suspend(ar, wow);
	return ar->hif_ops->suspend(ar, wow);
}
}


/*
 * Read from the ATH6KL through its diagnostic window. No cooperation from
 * the Target is required for this.
 */
static inline int ath6kl_hif_diag_read32(struct ath6kl *ar, u32 address,
					 u32 *value)
{
	return ar->hif_ops->diag_read32(ar, address, value);
}

/*
 * Write to the ATH6KL through its diagnostic window. No cooperation from
 * the Target is required for this.
 */
static inline int ath6kl_hif_diag_write32(struct ath6kl *ar, u32 address,
					  __le32 value)
{
	return ar->hif_ops->diag_write32(ar, address, value);
}

static inline int ath6kl_hif_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
static inline int ath6kl_hif_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
{
{
	return ar->hif_ops->bmi_read(ar, buf, len);
	return ar->hif_ops->bmi_read(ar, buf, len);
+2 −0
Original line number Original line Diff line number Diff line
@@ -244,6 +244,8 @@ struct ath6kl_hif_ops {
	void (*cleanup_scatter)(struct ath6kl *ar);
	void (*cleanup_scatter)(struct ath6kl *ar);
	int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow);
	int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow);
	int (*resume)(struct ath6kl *ar);
	int (*resume)(struct ath6kl *ar);
	int (*diag_read32)(struct ath6kl *ar, u32 address, u32 *value);
	int (*diag_write32)(struct ath6kl *ar, u32 address, __le32 value);
	int (*bmi_read)(struct ath6kl *ar, u8 *buf, u32 len);
	int (*bmi_read)(struct ath6kl *ar, u8 *buf, u32 len);
	int (*bmi_write)(struct ath6kl *ar, u8 *buf, u32 len);
	int (*bmi_write)(struct ath6kl *ar, u8 *buf, u32 len);
	int (*power_on)(struct ath6kl *ar);
	int (*power_on)(struct ath6kl *ar);
+4 −72
Original line number Original line Diff line number Diff line
@@ -175,64 +175,6 @@ void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie)
	ar->cookie_count++;
	ar->cookie_count++;
}
}


/* set the window address register (using 4-byte register access ). */
static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
{
	int status;
	s32 i;
	__le32 addr_val;

	/*
	 * Write bytes 1,2,3 of the register to set the upper address bytes,
	 * the LSB is written last to initiate the access cycle
	 */

	for (i = 1; i <= 3; i++) {
		/*
		 * Fill the buffer with the address byte value we want to
		 * hit 4 times. No need to worry about endianness as the
		 * same byte is copied to all four bytes of addr_val at
		 * any time.
		 */
		memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4);

		/*
		 * Hit each byte of the register address with a 4-byte
		 * write operation to the same address, this is a harmless
		 * operation.
		 */
		status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val,
					     4, HIF_WR_SYNC_BYTE_FIX);
		if (status)
			break;
	}

	if (status) {
		ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n",
			   addr, reg_addr);
		return status;
	}

	/*
	 * Write the address register again, this time write the whole
	 * 4-byte value. The effect here is that the LSB write causes the
	 * cycle to start, the extra 3 byte write to bytes 1,2,3 has no
	 * effect since we are writing the same values again
	 */
	addr_val = cpu_to_le32(addr);
	status = hif_read_write_sync(ar, reg_addr,
				     (u8 *)&(addr_val),
				     4, HIF_WR_SYNC_BYTE_INC);

	if (status) {
		ath6kl_err("failed to write 0x%x to window reg: 0x%X\n",
			   addr, reg_addr);
		return status;
	}

	return 0;
}

/*
/*
 * Read from the hardware through its diagnostic window. No cooperation
 * Read from the hardware through its diagnostic window. No cooperation
 * from the firmware is required for this.
 * from the firmware is required for this.
@@ -241,14 +183,7 @@ int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value)
{
{
	int ret;
	int ret;


	/* set window register to start read cycle */
	ret = ath6kl_hif_diag_read32(ar, address, value);
	ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address);
	if (ret)
		return ret;

	/* read the data */
	ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value,
				  sizeof(*value), HIF_RD_SYNC_BYTE_INC);
	if (ret) {
	if (ret) {
		ath6kl_warn("failed to read32 through diagnose window: %d\n",
		ath6kl_warn("failed to read32 through diagnose window: %d\n",
			    ret);
			    ret);
@@ -266,18 +201,15 @@ int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
{
{
	int ret;
	int ret;


	/* set write data */
	ret = ath6kl_hif_diag_write32(ar, address, value);
	ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value,

				  sizeof(value), HIF_WR_SYNC_BYTE_INC);
	if (ret) {
	if (ret) {
		ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
		ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
			   address, value);
			   address, value);
		return ret;
		return ret;
	}
	}


	/* set window register, which starts the write cycle */
	return 0;
	return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
				      address);
}
}


int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length)
+100 −0
Original line number Original line Diff line number Diff line
@@ -845,6 +845,104 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
	return 0;
	return 0;
}
}


/* set the window address register (using 4-byte register access ). */
static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
{
	int status;
	u8 addr_val[4];
	s32 i;

	/*
	 * Write bytes 1,2,3 of the register to set the upper address bytes,
	 * the LSB is written last to initiate the access cycle
	 */

	for (i = 1; i <= 3; i++) {
		/*
		 * Fill the buffer with the address byte value we want to
		 * hit 4 times.
		 */
		memset(addr_val, ((u8 *)&addr)[i], 4);

		/*
		 * Hit each byte of the register address with a 4-byte
		 * write operation to the same address, this is a harmless
		 * operation.
		 */
		status = ath6kl_sdio_read_write_sync(ar, reg_addr + i, addr_val,
					     4, HIF_WR_SYNC_BYTE_FIX);
		if (status)
			break;
	}

	if (status) {
		ath6kl_err("%s: failed to write initial bytes of 0x%x "
			   "to window reg: 0x%X\n", __func__,
			   addr, reg_addr);
		return status;
	}

	/*
	 * Write the address register again, this time write the whole
	 * 4-byte value. The effect here is that the LSB write causes the
	 * cycle to start, the extra 3 byte write to bytes 1,2,3 has no
	 * effect since we are writing the same values again
	 */
	status = ath6kl_sdio_read_write_sync(ar, reg_addr, (u8 *)(&addr),
				     4, HIF_WR_SYNC_BYTE_INC);

	if (status) {
		ath6kl_err("%s: failed to write 0x%x to window reg: 0x%X\n",
			   __func__, addr, reg_addr);
		return status;
	}

	return 0;
}

static int ath6kl_sdio_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
{
	int status;

	/* set window register to start read cycle */
	status = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS,
					address);

	if (status)
		return status;

	/* read the data */
	status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
				(u8 *)data, sizeof(u32), HIF_RD_SYNC_BYTE_INC);
	if (status) {
		ath6kl_err("%s: failed to read from window data addr\n",
			__func__);
		return status;
	}

	return status;
}

static int ath6kl_sdio_diag_write32(struct ath6kl *ar, u32 address,
				    __le32 data)
{
	int status;
	u32 val = (__force u32) data;

	/* set write data */
	status = ath6kl_sdio_read_write_sync(ar, WINDOW_DATA_ADDRESS,
				(u8 *) &val, sizeof(u32), HIF_WR_SYNC_BYTE_INC);
	if (status) {
		ath6kl_err("%s: failed to write 0x%x to window data addr\n",
			   __func__, data);
		return status;
	}

	/* set window register, which starts the write cycle */
	return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS,
				      address);
}

static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
{
{
	u32 addr;
	u32 addr;
@@ -1049,6 +1147,8 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
	.cleanup_scatter = ath6kl_sdio_cleanup_scatter,
	.cleanup_scatter = ath6kl_sdio_cleanup_scatter,
	.suspend = ath6kl_sdio_suspend,
	.suspend = ath6kl_sdio_suspend,
	.resume = ath6kl_sdio_resume,
	.resume = ath6kl_sdio_resume,
	.diag_read32 = ath6kl_sdio_diag_read32,
	.diag_write32 = ath6kl_sdio_diag_write32,
	.bmi_read = ath6kl_sdio_bmi_read,
	.bmi_read = ath6kl_sdio_bmi_read,
	.bmi_write = ath6kl_sdio_bmi_write,
	.bmi_write = ath6kl_sdio_bmi_write,
	.power_on = ath6kl_sdio_power_on,
	.power_on = ath6kl_sdio_power_on,