| /* |
| * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved. |
| */ |
| |
| /* |
| * The code contained herein is licensed under the GNU General Public |
| * License. You may obtain a copy of the GNU General Public License |
| * Version 2 or later at the following locations: |
| * |
| * http://www.opensource.org/licenses/gpl-license.html |
| * http://www.gnu.org/copyleft/gpl.html |
| */ |
| |
| #include <linux/delay.h> |
| #include <linux/err.h> |
| #include <linux/module.h> |
| #include <linux/of.h> |
| #include <linux/platform_device.h> |
| #include <linux/suspend.h> |
| |
| #include <linux/imx_sema4.h> |
| #include <linux/mcc_config_linux.h> |
| #include <linux/mcc_common.h> |
| #include <linux/mcc_api.h> |
| #include <linux/mcc_linux.h> |
| #include <linux/mcc_imx6sx.h> |
| |
| enum { |
| MCC_NODE_A9 = 0, |
| MCC_NODE_M4 = 0, |
| |
| MCC_A9_PORT = 1, |
| MCC_M4_PORT = 2, |
| }; |
| |
| /* mcc pingpong test */ |
| MCC_ENDPOINT mcc_endpoint_a9_pingpong = {0, MCC_NODE_A9, MCC_A9_PORT}; |
| MCC_ENDPOINT mcc_endpoint_m4_pingpong = {1, MCC_NODE_M4, MCC_M4_PORT}; |
| /* mcc can test */ |
| MCC_ENDPOINT mcc_endpoint_a9_can = {0, MCC_NODE_A9, MCC_A9_PORT}; |
| MCC_ENDPOINT mcc_endpoint_m4_can = {1, MCC_NODE_A9, MCC_A9_PORT}; |
| |
| struct mcc_pp_msg { |
| unsigned int data; |
| }; |
| |
| /* Set the max len of the can msg to be 1000 bytes */ |
| struct mcc_can_msg { |
| char data[MCC_ATTR_BUFFER_SIZE_IN_BYTES - 24]; |
| }; |
| |
| static ssize_t imx_mcc_can_test_en(struct device *dev, |
| struct device_attribute *attr, |
| const char *buf, size_t count) |
| { |
| u32 can_test_en; |
| int i = 0, ret = 0; |
| struct mcc_can_msg msg; |
| MCC_MEM_SIZE num_of_received_bytes; |
| MCC_INFO_STRUCT mcc_info; |
| |
| sscanf(buf, "%d\n", &can_test_en); |
| |
| if (can_test_en) { |
| pr_info("imx mcc can communication test begin.\n"); |
| ret = mcc_get_info(MCC_NODE_A9, &mcc_info); |
| if (ret) { |
| pr_err("failed to get mcc info.\n"); |
| return -EINVAL; |
| } |
| |
| ret = mcc_create_endpoint(&mcc_endpoint_a9_can, MCC_A9_PORT); |
| if (ret) { |
| pr_err("failed to create a9 mcc ep.\n"); |
| return -EINVAL; |
| } |
| |
| pr_info("\nA9 mcc prepares run, MCC version is %s\n", |
| mcc_info.version_string); |
| |
| while (i < 0x10000) { |
| i++; |
| /* |
| * wait for the "sleep" msg from the remote ep. |
| */ |
| ret = mcc_recv(&mcc_endpoint_m4_can, |
| &mcc_endpoint_a9_can, &msg, |
| sizeof(struct mcc_can_msg), |
| &num_of_received_bytes, 0xffffffff); |
| if (ret < 0) { |
| pr_err("A9 Main task recv error: %d\n", ret); |
| break; |
| } |
| pr_info("%s", msg.data); |
| } |
| |
| ret = mcc_destroy_endpoint(&mcc_endpoint_a9_can); |
| if (ret) { |
| pr_err("failed to destory a9 mcc ep.\n"); |
| return -EINVAL; |
| } else { |
| pr_info("destory a9 mcc ep.\n"); |
| } |
| } |
| |
| pr_info("imx mcc test end after %08d times recv tests.\n", i); |
| return count; |
| } |
| |
| static ssize_t imx_mcc_pingpong_en(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| u32 pingpong_en; |
| int i = 0, ret = 0; |
| struct timeval tv1, tv2, tv3; |
| u32 tv_count1 = 0, tv_count2 = 0; |
| struct mcc_pp_msg msg; |
| MCC_MEM_SIZE num_of_received_bytes; |
| MCC_INFO_STRUCT mcc_info; |
| |
| sscanf(buf, "%d\n", &pingpong_en); |
| if (pingpong_en) { |
| pr_info("imx mcc pingpong test begin.\n"); |
| ret = mcc_get_info(MCC_NODE_A9, &mcc_info); |
| if (ret) { |
| pr_err("failed to get mcc info.\n"); |
| return -EINVAL; |
| } |
| |
| ret = mcc_create_endpoint(&mcc_endpoint_a9_pingpong, |
| MCC_A9_PORT); |
| if (ret) { |
| pr_err("failed to create a9 mcc ep.\n"); |
| return -EINVAL; |
| } |
| |
| pr_info("\nA9 mcc prepares run, MCC version is %s\n", |
| mcc_info.version_string); |
| msg.data = 1; |
| while (i < 0x50000) { |
| i++; |
| i++; |
| /* |
| * wait until the remote endpoint is created by |
| * the other core |
| */ |
| if (pingpong_en > 1) |
| do_gettimeofday(&tv1); |
| |
| ret = mcc_send(&mcc_endpoint_a9_pingpong, |
| &mcc_endpoint_m4_pingpong, &msg, |
| sizeof(struct mcc_pp_msg), |
| 0xffffffff); |
| if (ret < 0) { |
| pr_err("A9 Main task send error: %d\n", ret); |
| break; |
| } |
| |
| if (pingpong_en > 1) { |
| do_gettimeofday(&tv2); |
| tv_count1 = (tv2.tv_sec - tv1.tv_sec) |
| * USEC_PER_SEC |
| + tv2.tv_usec - tv1.tv_usec; |
| } |
| while (MCC_ERR_ENDPOINT == ret) { |
| pr_err("\n send err ret %d, re-send\n", ret); |
| ret = mcc_send(&mcc_endpoint_a9_pingpong, |
| &mcc_endpoint_m4_pingpong, &msg, |
| sizeof(struct mcc_pp_msg), |
| 0xffffffff); |
| msleep(5000); |
| } |
| |
| if (pingpong_en > 1) |
| do_gettimeofday(&tv2); |
| |
| ret = mcc_recv(&mcc_endpoint_m4_pingpong, |
| &mcc_endpoint_a9_pingpong, &msg, |
| sizeof(struct mcc_pp_msg), |
| &num_of_received_bytes, 0xffffffff); |
| |
| if (pingpong_en > 1) { |
| do_gettimeofday(&tv3); |
| tv_count2 = (tv3.tv_sec - tv2.tv_sec) |
| * USEC_PER_SEC |
| + tv3.tv_usec - tv2.tv_usec; |
| pr_info("imx mcc: Data transfer speed tests" |
| "in pingpong. a9 -> m4:%08dus." |
| "a9 <- m4:%08dus.\n", |
| tv_count1, tv_count2); |
| } |
| |
| if (MCC_SUCCESS != ret) { |
| pr_err("A9 Main task receive error: %d\n", ret); |
| break; |
| } else { |
| pr_info("%08x Main task received a msg" |
| " from [%d, %d, %d] endpoint\n", i, |
| mcc_endpoint_m4_pingpong.core, |
| mcc_endpoint_m4_pingpong.node, |
| mcc_endpoint_m4_pingpong.port); |
| pr_info("Message: Size=0x%08x, data = 0x%08x\n", |
| num_of_received_bytes, msg.data); |
| msg.data++; |
| } |
| } |
| ret = mcc_destroy_endpoint(&mcc_endpoint_a9_pingpong); |
| if (ret) { |
| pr_err("failed to destory a9 mcc ep.\n"); |
| return ret; |
| } else { |
| pr_info("destory a9 mcc ep.\n"); |
| } |
| pr_info("imx mcc test end after %08d times tests.\n", i/2); |
| } |
| |
| if (ret) |
| return ret; |
| else |
| return count; |
| } |
| |
| static DEVICE_ATTR(pingpong_en, S_IWUGO, NULL, imx_mcc_pingpong_en); |
| static DEVICE_ATTR(can_test_en, S_IWUGO, NULL, imx_mcc_can_test_en); |
| |
| static struct attribute *imx_mcc_attrs[] = { |
| &dev_attr_pingpong_en.attr, |
| &dev_attr_can_test_en.attr, |
| NULL |
| }; |
| |
| static struct attribute_group imx_mcc_attrgroup = { |
| .attrs = imx_mcc_attrs, |
| }; |
| |
| static int imx_mcc_test_probe(struct platform_device *pdev) |
| { |
| int ret = 0; |
| MCC_INFO_STRUCT mcc_info; |
| |
| ret = mcc_initialize(MCC_NODE_A9); |
| if (ret) { |
| pr_err("failed to initialize mcc.\n"); |
| ret = -EINVAL; |
| return ret; |
| } |
| |
| ret = mcc_get_info(MCC_NODE_A9, &mcc_info); |
| if (ret) { |
| pr_err("failed to get mcc info.\n"); |
| ret = -EINVAL; |
| goto out_node; |
| } |
| pr_info("\nA9 mcc prepares run, MCC version is %s\n", |
| mcc_info.version_string); |
| |
| if (strcmp(mcc_info.version_string, MCC_VERSION_STRING) != 0) { |
| pr_err("\nError, different versions of the MCC library"); |
| pr_err("is used on each core!\n"); |
| pr_err("\nApplication is stopped now.\n"); |
| ret = -EINVAL; |
| goto out_node; |
| } |
| |
| /* add attributes for device. */ |
| ret = sysfs_create_group(&pdev->dev.kobj, &imx_mcc_attrgroup); |
| if (ret) |
| goto out_node; |
| |
| return ret; |
| |
| out_node: |
| mcc_destroy(MCC_NODE_A9); |
| |
| return ret; |
| } |
| |
| static int imx_mcc_test_remove(struct platform_device *pdev) |
| { |
| return 0; |
| } |
| |
| static const struct of_device_id imx_mcc_test_dt_ids[] = { |
| { .compatible = "fsl,imx6sx-mcc-test", }, |
| { /* sentinel */ } |
| }; |
| MODULE_DEVICE_TABLE(of, imx_mcc_test_dt_ids); |
| |
| static struct platform_driver imx_mcc_test_driver = { |
| .driver = { |
| .owner = THIS_MODULE, |
| .name = "imx6sx-mcc-test", |
| .of_match_table = imx_mcc_test_dt_ids, |
| }, |
| .probe = imx_mcc_test_probe, |
| .remove = imx_mcc_test_remove, |
| }; |
| |
| static int __init imx_mcc_test_init(void) |
| { |
| int ret; |
| |
| ret = platform_driver_register(&imx_mcc_test_driver); |
| if (ret) |
| pr_err("failed to register imx mcc test driver.\n"); |
| else |
| pr_info("imx mcc test is registered.\n"); |
| return ret; |
| } |
| late_initcall(imx_mcc_test_init); |
| |
| MODULE_AUTHOR("Freescale Semiconductor, Inc."); |
| MODULE_DESCRIPTION("IMX MCC test driver"); |
| MODULE_LICENSE("GPL"); |