mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	soc: hisilicon: kunpeng_hccs: Support the platform with PCC type3 and interrupt ack
Support the platform with PCC type3 and interrupt ack. And a version specific structure is introduced to handle the difference between the device in the code. Signed-off-by: Huisong Li <lihuisong@huawei.com> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
This commit is contained in:
		
							parent
							
								
									a07d8fc358
								
							
						
					
					
						commit
						be2f78a8a6
					
				
					 2 changed files with 125 additions and 25 deletions
				
			
		|  | @ -110,6 +110,14 @@ static void hccs_chan_tx_done(struct mbox_client *cl, void *msg, int ret) | ||||||
| 			 *(u8 *)msg, ret); | 			 *(u8 *)msg, ret); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void hccs_pcc_rx_callback(struct mbox_client *cl, void *mssg) | ||||||
|  | { | ||||||
|  | 	struct hccs_mbox_client_info *cl_info = | ||||||
|  | 			container_of(cl, struct hccs_mbox_client_info, client); | ||||||
|  | 
 | ||||||
|  | 	complete(&cl_info->done); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void hccs_unregister_pcc_channel(struct hccs_dev *hdev) | static void hccs_unregister_pcc_channel(struct hccs_dev *hdev) | ||||||
| { | { | ||||||
| 	struct hccs_mbox_client_info *cl_info = &hdev->cl_info; | 	struct hccs_mbox_client_info *cl_info = &hdev->cl_info; | ||||||
|  | @ -131,6 +139,9 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev) | ||||||
| 	cl->tx_block = false; | 	cl->tx_block = false; | ||||||
| 	cl->knows_txdone = true; | 	cl->knows_txdone = true; | ||||||
| 	cl->tx_done = hccs_chan_tx_done; | 	cl->tx_done = hccs_chan_tx_done; | ||||||
|  | 	cl->rx_callback = hdev->verspec_data->rx_callback; | ||||||
|  | 	init_completion(&cl_info->done); | ||||||
|  | 
 | ||||||
| 	pcc_chan = pcc_mbox_request_channel(cl, hdev->chan_id); | 	pcc_chan = pcc_mbox_request_channel(cl, hdev->chan_id); | ||||||
| 	if (IS_ERR(pcc_chan)) { | 	if (IS_ERR(pcc_chan)) { | ||||||
| 		dev_err(dev, "PPC channel request failed.\n"); | 		dev_err(dev, "PPC channel request failed.\n"); | ||||||
|  | @ -147,10 +158,16 @@ static int hccs_register_pcc_channel(struct hccs_dev *hdev) | ||||||
| 	 */ | 	 */ | ||||||
| 	cl_info->deadline_us = | 	cl_info->deadline_us = | ||||||
| 			HCCS_PCC_CMD_WAIT_RETRIES_NUM * pcc_chan->latency; | 			HCCS_PCC_CMD_WAIT_RETRIES_NUM * pcc_chan->latency; | ||||||
| 	if (cl_info->mbox_chan->mbox->txdone_irq) { | 	if (!hdev->verspec_data->has_txdone_irq && | ||||||
|  | 	    cl_info->mbox_chan->mbox->txdone_irq) { | ||||||
| 		dev_err(dev, "PCC IRQ in PCCT is enabled.\n"); | 		dev_err(dev, "PCC IRQ in PCCT is enabled.\n"); | ||||||
| 		rc = -EINVAL; | 		rc = -EINVAL; | ||||||
| 		goto err_mbx_channel_free; | 		goto err_mbx_channel_free; | ||||||
|  | 	} else if (hdev->verspec_data->has_txdone_irq && | ||||||
|  | 		   !cl_info->mbox_chan->mbox->txdone_irq) { | ||||||
|  | 		dev_err(dev, "PCC IRQ in PCCT isn't supported.\n"); | ||||||
|  | 		rc = -EINVAL; | ||||||
|  | 		goto err_mbx_channel_free; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (pcc_chan->shmem_base_addr) { | 	if (pcc_chan->shmem_base_addr) { | ||||||
|  | @ -172,7 +189,7 @@ out: | ||||||
| 	return rc; | 	return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int hccs_check_chan_cmd_complete(struct hccs_dev *hdev) | static int hccs_wait_cmd_complete_by_poll(struct hccs_dev *hdev) | ||||||
| { | { | ||||||
| 	struct hccs_mbox_client_info *cl_info = &hdev->cl_info; | 	struct hccs_mbox_client_info *cl_info = &hdev->cl_info; | ||||||
| 	struct acpi_pcct_shared_memory __iomem *comm_base = | 	struct acpi_pcct_shared_memory __iomem *comm_base = | ||||||
|  | @ -194,30 +211,74 @@ static int hccs_check_chan_cmd_complete(struct hccs_dev *hdev) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int hccs_wait_cmd_complete_by_irq(struct hccs_dev *hdev) | ||||||
|  | { | ||||||
|  | 	struct hccs_mbox_client_info *cl_info = &hdev->cl_info; | ||||||
|  | 
 | ||||||
|  | 	if (!wait_for_completion_timeout(&cl_info->done, | ||||||
|  | 			usecs_to_jiffies(cl_info->deadline_us))) { | ||||||
|  | 		dev_err(hdev->dev, "PCC command executed timeout!\n"); | ||||||
|  | 		return -ETIMEDOUT; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void hccs_fill_pcc_shared_mem_region(struct hccs_dev *hdev, | ||||||
|  | 						   u8 cmd, | ||||||
|  | 						   struct hccs_desc *desc, | ||||||
|  | 						   void __iomem *comm_space, | ||||||
|  | 						   u16 space_size) | ||||||
|  | { | ||||||
|  | 	struct acpi_pcct_shared_memory tmp = { | ||||||
|  | 		.signature = PCC_SIGNATURE | hdev->chan_id, | ||||||
|  | 		.command = cmd, | ||||||
|  | 		.status = 0, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	memcpy_toio(hdev->cl_info.pcc_comm_addr, (void *)&tmp, | ||||||
|  | 		    sizeof(struct acpi_pcct_shared_memory)); | ||||||
|  | 
 | ||||||
|  | 	/* Copy the message to the PCC comm space */ | ||||||
|  | 	memcpy_toio(comm_space, (void *)desc, space_size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void hccs_fill_ext_pcc_shared_mem_region(struct hccs_dev *hdev, | ||||||
|  | 						       u8 cmd, | ||||||
|  | 						       struct hccs_desc *desc, | ||||||
|  | 						       void __iomem *comm_space, | ||||||
|  | 						       u16 space_size) | ||||||
|  | { | ||||||
|  | 	struct acpi_pcct_ext_pcc_shared_memory tmp = { | ||||||
|  | 		.signature = PCC_SIGNATURE | hdev->chan_id, | ||||||
|  | 		.flags = PCC_CMD_COMPLETION_NOTIFY, | ||||||
|  | 		.length = HCCS_PCC_SHARE_MEM_BYTES, | ||||||
|  | 		.command = cmd, | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	memcpy_toio(hdev->cl_info.pcc_comm_addr, (void *)&tmp, | ||||||
|  | 		    sizeof(struct acpi_pcct_ext_pcc_shared_memory)); | ||||||
|  | 
 | ||||||
|  | 	/* Copy the message to the PCC comm space */ | ||||||
|  | 	memcpy_toio(comm_space, (void *)desc, space_size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, | static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, | ||||||
| 			     struct hccs_desc *desc) | 			     struct hccs_desc *desc) | ||||||
| { | { | ||||||
|  | 	const struct hccs_verspecific_data *verspec_data = hdev->verspec_data; | ||||||
| 	struct hccs_mbox_client_info *cl_info = &hdev->cl_info; | 	struct hccs_mbox_client_info *cl_info = &hdev->cl_info; | ||||||
| 	void __iomem *comm_space = cl_info->pcc_comm_addr + |  | ||||||
| 					sizeof(struct acpi_pcct_shared_memory); |  | ||||||
| 	struct hccs_fw_inner_head *fw_inner_head; | 	struct hccs_fw_inner_head *fw_inner_head; | ||||||
| 	struct acpi_pcct_shared_memory tmp = {0}; | 	void __iomem *comm_space; | ||||||
| 	u16 comm_space_size; | 	u16 space_size; | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	/* Write signature for this subspace */ | 	comm_space = cl_info->pcc_comm_addr + verspec_data->shared_mem_size; | ||||||
| 	tmp.signature = PCC_SIGNATURE | hdev->chan_id; | 	space_size = HCCS_PCC_SHARE_MEM_BYTES - verspec_data->shared_mem_size; | ||||||
| 	/* Write to the shared command region */ | 	verspec_data->fill_pcc_shared_mem(hdev, cmd, desc, | ||||||
| 	tmp.command = cmd; | 					  comm_space, space_size); | ||||||
| 	/* Clear cmd complete bit */ | 	if (verspec_data->has_txdone_irq) | ||||||
| 	tmp.status = 0; | 		reinit_completion(&cl_info->done); | ||||||
| 	memcpy_toio(cl_info->pcc_comm_addr, (void *)&tmp, |  | ||||||
| 			sizeof(struct acpi_pcct_shared_memory)); |  | ||||||
| 
 |  | ||||||
| 	/* Copy the message to the PCC comm space */ |  | ||||||
| 	comm_space_size = HCCS_PCC_SHARE_MEM_BYTES - |  | ||||||
| 				sizeof(struct acpi_pcct_shared_memory); |  | ||||||
| 	memcpy_toio(comm_space, (void *)desc, comm_space_size); |  | ||||||
| 
 | 
 | ||||||
| 	/* Ring doorbell */ | 	/* Ring doorbell */ | ||||||
| 	ret = mbox_send_message(cl_info->mbox_chan, &cmd); | 	ret = mbox_send_message(cl_info->mbox_chan, &cmd); | ||||||
|  | @ -227,13 +288,12 @@ static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, | ||||||
| 		goto end; | 		goto end; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Wait for completion */ | 	ret = verspec_data->wait_cmd_complete(hdev); | ||||||
| 	ret = hccs_check_chan_cmd_complete(hdev); |  | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto end; | 		goto end; | ||||||
| 
 | 
 | ||||||
| 	/* Copy response data */ | 	/* Copy response data */ | ||||||
| 	memcpy_fromio((void *)desc, comm_space, comm_space_size); | 	memcpy_fromio((void *)desc, comm_space, space_size); | ||||||
| 	fw_inner_head = &desc->rsp.fw_inner_head; | 	fw_inner_head = &desc->rsp.fw_inner_head; | ||||||
| 	if (fw_inner_head->retStatus) { | 	if (fw_inner_head->retStatus) { | ||||||
| 		dev_err(hdev->dev, "Execute PCC command failed, error code = %u.\n", | 		dev_err(hdev->dev, "Execute PCC command failed, error code = %u.\n", | ||||||
|  | @ -242,7 +302,10 @@ static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| end: | end: | ||||||
| 	mbox_client_txdone(cl_info->mbox_chan, ret); | 	if (verspec_data->has_txdone_irq) | ||||||
|  | 		mbox_chan_txdone(cl_info->mbox_chan, ret); | ||||||
|  | 	else | ||||||
|  | 		mbox_client_txdone(cl_info->mbox_chan, ret); | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1213,6 +1276,11 @@ static int hccs_probe(struct platform_device *pdev) | ||||||
| 	hdev->dev = &pdev->dev; | 	hdev->dev = &pdev->dev; | ||||||
| 	platform_set_drvdata(pdev, hdev); | 	platform_set_drvdata(pdev, hdev); | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Here would never be failure as the driver and device has been matched. | ||||||
|  | 	 */ | ||||||
|  | 	hdev->verspec_data = acpi_device_get_match_data(hdev->dev); | ||||||
|  | 
 | ||||||
| 	mutex_init(&hdev->lock); | 	mutex_init(&hdev->lock); | ||||||
| 	rc = hccs_get_pcc_chan_id(hdev); | 	rc = hccs_get_pcc_chan_id(hdev); | ||||||
| 	if (rc) | 	if (rc) | ||||||
|  | @ -1249,9 +1317,26 @@ static void hccs_remove(struct platform_device *pdev) | ||||||
| 	hccs_unregister_pcc_channel(hdev); | 	hccs_unregister_pcc_channel(hdev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static const struct hccs_verspecific_data hisi04b1_verspec_data = { | ||||||
|  | 	.rx_callback = NULL, | ||||||
|  | 	.wait_cmd_complete = hccs_wait_cmd_complete_by_poll, | ||||||
|  | 	.fill_pcc_shared_mem = hccs_fill_pcc_shared_mem_region, | ||||||
|  | 	.shared_mem_size = sizeof(struct acpi_pcct_shared_memory), | ||||||
|  | 	.has_txdone_irq = false, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct hccs_verspecific_data hisi04b2_verspec_data = { | ||||||
|  | 	.rx_callback = hccs_pcc_rx_callback, | ||||||
|  | 	.wait_cmd_complete = hccs_wait_cmd_complete_by_irq, | ||||||
|  | 	.fill_pcc_shared_mem = hccs_fill_ext_pcc_shared_mem_region, | ||||||
|  | 	.shared_mem_size = sizeof(struct acpi_pcct_ext_pcc_shared_memory), | ||||||
|  | 	.has_txdone_irq = true, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static const struct acpi_device_id hccs_acpi_match[] = { | static const struct acpi_device_id hccs_acpi_match[] = { | ||||||
| 	{ "HISI04B1"}, | 	{ "HISI04B1", (unsigned long)&hisi04b1_verspec_data}, | ||||||
| 	{ ""}, | 	{ "HISI04B2", (unsigned long)&hisi04b2_verspec_data}, | ||||||
|  | 	{ } | ||||||
| }; | }; | ||||||
| MODULE_DEVICE_TABLE(acpi, hccs_acpi_match); | MODULE_DEVICE_TABLE(acpi, hccs_acpi_match); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -51,11 +51,26 @@ struct hccs_mbox_client_info { | ||||||
| 	struct pcc_mbox_chan *pcc_chan; | 	struct pcc_mbox_chan *pcc_chan; | ||||||
| 	u64 deadline_us; | 	u64 deadline_us; | ||||||
| 	void __iomem *pcc_comm_addr; | 	void __iomem *pcc_comm_addr; | ||||||
|  | 	struct completion done; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct hccs_desc; | ||||||
|  | 
 | ||||||
|  | struct hccs_verspecific_data { | ||||||
|  | 	void (*rx_callback)(struct mbox_client *cl, void *mssg); | ||||||
|  | 	int (*wait_cmd_complete)(struct hccs_dev *hdev); | ||||||
|  | 	void (*fill_pcc_shared_mem)(struct hccs_dev *hdev, | ||||||
|  | 				    u8 cmd, struct hccs_desc *desc, | ||||||
|  | 				    void __iomem *comm_space, | ||||||
|  | 				    u16 space_size); | ||||||
|  | 	u16 shared_mem_size; | ||||||
|  | 	bool has_txdone_irq; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct hccs_dev { | struct hccs_dev { | ||||||
| 	struct device *dev; | 	struct device *dev; | ||||||
| 	struct acpi_device *acpi_dev; | 	struct acpi_device *acpi_dev; | ||||||
|  | 	const struct hccs_verspecific_data *verspec_data; | ||||||
| 	u64 caps; | 	u64 caps; | ||||||
| 	u8 chip_num; | 	u8 chip_num; | ||||||
| 	struct hccs_chip_info *chips; | 	struct hccs_chip_info *chips; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Huisong Li
						Huisong Li