From 5aeedebc33849efbbee2d422a4c7da8194e1b670 Mon Sep 17 00:00:00 2001 From: Angelo Dureghello Date: Sat, 21 May 2016 12:05:49 +0200 Subject: dm: add manual relocation for devices Some architectures as m68k still need to use CONFIG_NEEDS_MANUAL_RELOC, and are not still using the device tree. Signed-off-by: Angelo Dureghello Acked-by: Simon Glass --- drivers/core/root.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/core/root.c b/drivers/core/root.c index 13c2713e61..95886add23 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -122,6 +122,20 @@ void fix_uclass(void) entry->ops += gd->reloc_off; } } + +void fix_devices(void) +{ + struct driver_info *dev = + ll_entry_start(struct driver_info, driver_info); + const int n_ents = ll_entry_count(struct driver_info, driver_info); + struct driver_info *entry; + + for (entry = dev; entry != dev + n_ents; entry++) { + if (entry->platdata) + entry->platdata += gd->reloc_off; + } +} + #endif int dm_init(void) @@ -137,6 +151,7 @@ int dm_init(void) #if defined(CONFIG_NEEDS_MANUAL_RELOC) fix_drivers(); fix_uclass(); + fix_devices(); #endif ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST); -- cgit v1.2.1 From fc76b698736efa9d52e06aa09c03dc8ef10fd581 Mon Sep 17 00:00:00 2001 From: "mario.six@gdsys.cc" Date: Mon, 23 May 2016 09:54:56 +0200 Subject: gpio: pca953x: Fix register reading past 8th GPIO A bug in the pca953x driver prevents correct reading of GPIO input values beyond the 8th GPIO; all values are reported as zero. Setting of GPIO output values is not affected. This patch fixes the reading behavior. Signed-off-by: Mario Six Reviewed-by: Peng Fan Acked-by: Simon Glass --- drivers/gpio/pca953x_gpio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c index 065b181bd2..0410add518 100644 --- a/drivers/gpio/pca953x_gpio.c +++ b/drivers/gpio/pca953x_gpio.c @@ -148,11 +148,13 @@ static int pca953x_get_value(struct udevice *dev, unsigned offset) int ret; u8 val = 0; + int off = offset % BANK_SZ; + ret = pca953x_read_single(dev, PCA953X_INPUT, &val, offset); if (ret) return ret; - return (val >> offset) & 0x1; + return (val >> off) & 0x1; } static int pca953x_set_value(struct udevice *dev, unsigned offset, -- cgit v1.2.1 From 6feed2a5aefb7fd0ac443a50bfe00625000bdd34 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 23 May 2016 05:40:55 -0400 Subject: lib/libfdt/: General aesthetic/style fixes. A number of style fixes across the files in this directory, including: * Correct invalid kernel-doc content. * Tidy up massive comment in fdt_region.c. * Use correct spelling of "U-Boot". * Replace tests of "! " with "!". * Replace "libfdt_env.h" with . Signed-off-by: Robert P. J. Day Acked-by: Simon Glass --- lib/libfdt/Makefile | 12 +++- lib/libfdt/README | 16 ++--- lib/libfdt/fdt.c | 2 +- lib/libfdt/fdt_addresses.c | 2 +- lib/libfdt/fdt_empty_tree.c | 3 +- lib/libfdt/fdt_region.c | 144 +++++++++++++++++++++++--------------------- lib/libfdt/fdt_ro.c | 10 +-- lib/libfdt/fdt_rw.c | 6 +- lib/libfdt/fdt_strerror.c | 2 +- lib/libfdt/fdt_sw.c | 3 +- lib/libfdt/fdt_wip.c | 6 +- 11 files changed, 109 insertions(+), 97 deletions(-) diff --git a/lib/libfdt/Makefile b/lib/libfdt/Makefile index 934d6142c3..8b86c15904 100644 --- a/lib/libfdt/Makefile +++ b/lib/libfdt/Makefile @@ -5,5 +5,13 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_sw.o fdt_wip.o \ - fdt_empty_tree.o fdt_addresses.o fdt_region.o +obj-y += \ + fdt.o \ + fdt_ro.o \ + fdt_rw.o \ + fdt_strerror.o \ + fdt_sw.o \ + fdt_wip.o \ + fdt_empty_tree.o \ + fdt_addresses.o \ + fdt_region.o diff --git a/lib/libfdt/README b/lib/libfdt/README index e0598761f9..db40ab25e8 100644 --- a/lib/libfdt/README +++ b/lib/libfdt/README @@ -1,5 +1,5 @@ The libfdt functionality was written by David Gibson. The original -source came from the git repository: +source came from the Git repository: URL: git://ozlabs.org/home/dgibson/git/libfdt.git @@ -11,13 +11,15 @@ commit 857f54e79f74429af20c2b5ecc00ee98af6a3b8b tree 2f648f0f88225a51ded452968d28b4402df8ade0 parent 07a12a08005f3b5cd9337900a6551e450c07b515 -To adapt for u-boot usage, only the applicable files were copied and -imported into the u-boot git repository. +To adapt for U-Boot usage, only the applicable files were copied and +imported into the U-Boot Git repository. + Omitted: -* GPL - u-boot comes with a copy of the GPL license -* test subdirectory - not directly useful for u-boot -After importing, other customizations were performed. See the git log -for details. + * GPL - U-Boot comes with a copy of the GPL license + * test subdirectory - not directly useful for U-Boot + +After importing, other customizations were performed. See the +"git log" for details. Jerry Van Baren diff --git a/lib/libfdt/fdt.c b/lib/libfdt/fdt.c index e146aba6eb..96017a15a2 100644 --- a/lib/libfdt/fdt.c +++ b/lib/libfdt/fdt.c @@ -3,7 +3,7 @@ * Copyright (C) 2006 David Gibson, IBM Corporation. * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ -#include "libfdt_env.h" +#include #ifndef USE_HOSTCC #include diff --git a/lib/libfdt/fdt_addresses.c b/lib/libfdt/fdt_addresses.c index 76054d98e5..b6bc66ea32 100644 --- a/lib/libfdt/fdt_addresses.c +++ b/lib/libfdt/fdt_addresses.c @@ -3,7 +3,7 @@ * Copyright (C) 2014 David Gibson * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ -#include "libfdt_env.h" +#include #ifndef USE_HOSTCC #include diff --git a/lib/libfdt/fdt_empty_tree.c b/lib/libfdt/fdt_empty_tree.c index 34f1c84431..6fde1eb9ed 100644 --- a/lib/libfdt/fdt_empty_tree.c +++ b/lib/libfdt/fdt_empty_tree.c @@ -3,8 +3,7 @@ * Copyright (C) 2012 David Gibson, IBM Corporation. * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ -#include "libfdt_env.h" - +#include #include #include diff --git a/lib/libfdt/fdt_region.c b/lib/libfdt/fdt_region.c index 747d8bb86a..d2ce4c1c53 100644 --- a/lib/libfdt/fdt_region.c +++ b/lib/libfdt/fdt_region.c @@ -5,7 +5,7 @@ * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ -#include "libfdt_env.h" +#include #ifndef USE_HOSTCC #include @@ -18,14 +18,13 @@ /** * fdt_add_region() - Add a new region to our list + * @info: State information + * @offset: Start offset of region + * @size: Size of region * * The region is added if there is space, but in any case we increment the * count. If permitted, and the new region overlaps the last one, we merge * them. - * - * @info: State information - * @offset: Start offset of region - * @size: Size of region */ static int fdt_add_region(struct fdt_region_state *info, int offset, int size) { @@ -119,6 +118,8 @@ int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count, /** * fdt_include_supernodes() - Include supernodes required by this node + * @info: State information + * @depth: Current stack depth * * When we decided to include a node or property which is not at the top * level, this function forces the inclusion of higher level nodes. For @@ -131,9 +132,6 @@ int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count, * * If we decide to include testing then we need the root node to have a valid * tree. This function adds those regions. - * - * @info: State information - * @depth: Current stack depth */ static int fdt_include_supernodes(struct fdt_region_state *info, int depth) { @@ -203,72 +201,78 @@ int fdt_first_region(const void *fdt, path, path_len, flags, info); } -/* - * Theory of operation +/*********************************************************************** + * + * Theory of operation + * + * Note: in this description 'included' means that a node (or other part + * of the tree) should be included in the region list, i.e. it will have + * a region which covers its part of the tree. + * + * This function maintains some state from the last time it is called. + * It checks the next part of the tree that it is supposed to look at + * (p.nextoffset) to see if that should be included or not. When it + * finds something to include, it sets info->start to its offset. This + * marks the start of the region we want to include. + * + * Once info->start is set to the start (i.e. not -1), we continue + * scanning until we find something that we don't want included. This + * will be the end of a region. At this point we can close off the + * region and add it to the list. So we do so, and reset info->start + * to -1. + * + * One complication here is that we want to merge regions. So when we + * come to add another region later, we may in fact merge it with the + * previous one if one ends where the other starts. + * + * The function fdt_add_region() will return -1 if it fails to add the + * region, because we already have a region ready to be returned, and + * the new one cannot be merged in with it. In this case, we must return + * the region we found, and wait for another call to this function. + * When it comes, we will repeat the processing of the tag and again + * try to add a region. This time it will succeed. + * + * The current state of the pointers (stack, offset, etc.) is maintained + * in a ptrs member. At the start of every loop iteration we make a copy + * of it. The copy is then updated as the tag is processed. Only if we + * get to the end of the loop iteration (and successfully call + * fdt_add_region() if we need to) can we commit the changes we have + * made to these pointers. For example, if we see an FDT_END_NODE tag, + * we will decrement the depth value. But if we need to add a region + * for this tag (let's say because the previous tag is included and this + * FDT_END_NODE tag is not included) then we will only commit the result + * if we were able to add the region. That allows us to retry again next + * time. + * + * We keep track of a variable called 'want' which tells us what we want + * to include when there is no specific information provided by the + * h_include function for a particular property. This basically handles + * the inclusion of properties which are pulled in by virtue of the node + * they are in. So if you include a node, its properties are also + * included. In this case 'want' will be WANT_NODES_AND_PROPS. The + * FDT_REG_DIRECT_SUBNODES feature also makes use of 'want'. While we + * are inside the subnode, 'want' will be set to WANT_NODES_ONLY, so + * that only the subnode's FDT_BEGIN_NODE and FDT_END_NODE tags will be + * included, and properties will be skipped. If WANT_NOTHING is + * selected, then we will just rely on what the h_include() function + * tells us. * + * Using 'want' we work out 'include', which tells us whether this + * current tag should be included or not. As you can imagine, if the + * value of 'include' changes, that means we are on a boundary between + * nodes to include and nodes to exclude. At this point we either close + * off a previous region and add it to the list, or mark the start of a + * new region. * + * Apart from the nodes, we have mem_rsvmap, the FDT_END tag and the + * string list. Each of these dealt with as a whole (i.e. we create a + * region for each if it is to be included). For mem_rsvmap we don't + * allow it to merge with the first struct region. For the stringlist, + * we don't allow it to merge with the last struct region (which + * contains at minimum the FDT_END tag). * + *********************************************************************/ -Note: in this description 'included' means that a node (or other part of -the tree) should be included in the region list, i.e. it will have a region -which covers its part of the tree. - -This function maintains some state from the last time it is called. It -checks the next part of the tree that it is supposed to look at -(p.nextoffset) to see if that should be included or not. When it finds -something to include, it sets info->start to its offset. This marks the -start of the region we want to include. - -Once info->start is set to the start (i.e. not -1), we continue scanning -until we find something that we don't want included. This will be the end -of a region. At this point we can close off the region and add it to the -list. So we do so, and reset info->start to -1. - -One complication here is that we want to merge regions. So when we come to -add another region later, we may in fact merge it with the previous one if -one ends where the other starts. - -The function fdt_add_region() will return -1 if it fails to add the region, -because we already have a region ready to be returned, and the new one -cannot be merged in with it. In this case, we must return the region we -found, and wait for another call to this function. When it comes, we will -repeat the processing of the tag and again try to add a region. This time it -will succeed. - -The current state of the pointers (stack, offset, etc.) is maintained in -a ptrs member. At the start of every loop iteration we make a copy of it. -The copy is then updated as the tag is processed. Only if we get to the end -of the loop iteration (and successfully call fdt_add_region() if we need -to) can we commit the changes we have made to these pointers. For example, -if we see an FDT_END_NODE tag we will decrement the depth value. But if we -need to add a region for this tag (let's say because the previous tag is -included and this FDT_END_NODE tag is not included) then we will only commit -the result if we were able to add the region. That allows us to retry again -next time. - -We keep track of a variable called 'want' which tells us what we want to -include when there is no specific information provided by the h_include -function for a particular property. This basically handles the inclusion of -properties which are pulled in by virtue of the node they are in. So if you -include a node, its properties are also included. In this case 'want' will -be WANT_NODES_AND_PROPS. The FDT_REG_DIRECT_SUBNODES feature also makes use -of 'want'. While we are inside the subnode, 'want' will be set to -WANT_NODES_ONLY, so that only the subnode's FDT_BEGIN_NODE and FDT_END_NODE -tags will be included, and properties will be skipped. If WANT_NOTHING is -selected, then we will just rely on what the h_include() function tells us. - -Using 'want' we work out 'include', which tells us whether this current tag -should be included or not. As you can imagine, if the value of 'include' -changes, that means we are on a boundary between nodes to include and nodes -to exclude. At this point we either close off a previous region and add it -to the list, or mark the start of a new region. - -Apart from the nodes, we have mem_rsvmap, the FDT_END tag and the string -list. Each of these dealt with as a whole (i.e. we create a region for each -if it is to be included). For mem_rsvmap we don't allow it to merge with -the first struct region. For the stringlist we don't allow it to merge with -the last struct region (which contains at minimum the FDT_END tag). -*/ int fdt_next_region(const void *fdt, int (*h_include)(void *priv, const void *fdt, int offset, int type, const char *data, int size), diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c index 7b0777b67e..12214c2dc2 100644 --- a/lib/libfdt/fdt_ro.c +++ b/lib/libfdt/fdt_ro.c @@ -3,7 +3,7 @@ * Copyright (C) 2006 David Gibson, IBM Corporation. * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ -#include "libfdt_env.h" +#include #ifndef USE_HOSTCC #include @@ -19,7 +19,7 @@ static int _fdt_nodename_eq(const void *fdt, int offset, { const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); - if (! p) + if (!p) /* short match */ return 0; @@ -115,7 +115,7 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, /* * Find the next of path seperator, note we need to search for both '/' and ':' - * and then take the first one so that we do the rigth thing for e.g. + * and then take the first one so that we do the right thing for e.g. * "foo/bar:option" and "bar:option/otheroption", both of which happen, so * first searching for either ':' or '/' does not work. */ @@ -163,7 +163,7 @@ int fdt_path_offset(const void *fdt, const char *path) if (*p == '\0' || *p == ':') return offset; q = fdt_path_next_seperator(p); - if (! q) + if (!q) q = end; offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); @@ -273,7 +273,7 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const struct fdt_property *prop; prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); - if (! prop) + if (!prop) return NULL; return prop->data; diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c index 1a358a8ca0..e7321ccae4 100644 --- a/lib/libfdt/fdt_rw.c +++ b/lib/libfdt/fdt_rw.c @@ -3,7 +3,7 @@ * Copyright (C) 2006 David Gibson, IBM Corporation. * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ -#include "libfdt_env.h" +#include #ifndef USE_HOSTCC #include @@ -168,7 +168,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, int err; *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); - if (! (*prop)) + if (!(*prop)) return oldlen; if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), @@ -283,7 +283,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name) FDT_RW_CHECK_HEADER(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &len); - if (! prop) + if (!prop) return len; proplen = sizeof(*prop) + FDT_TAGALIGN(len); diff --git a/lib/libfdt/fdt_strerror.c b/lib/libfdt/fdt_strerror.c index 2f3cc243db..3b7e1683d0 100644 --- a/lib/libfdt/fdt_strerror.c +++ b/lib/libfdt/fdt_strerror.c @@ -3,7 +3,7 @@ * Copyright (C) 2006 David Gibson, IBM Corporation. * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ -#include "libfdt_env.h" +#include #ifndef USE_HOSTCC #include diff --git a/lib/libfdt/fdt_sw.c b/lib/libfdt/fdt_sw.c index 345a3acbf8..70fd026550 100644 --- a/lib/libfdt/fdt_sw.c +++ b/lib/libfdt/fdt_sw.c @@ -3,8 +3,7 @@ * Copyright (C) 2006 David Gibson, IBM Corporation. * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ -#include "libfdt_env.h" - +#include #include #include diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c index 3f2dfa573b..9fe988655f 100644 --- a/lib/libfdt/fdt_wip.c +++ b/lib/libfdt/fdt_wip.c @@ -3,7 +3,7 @@ * Copyright (C) 2006 David Gibson, IBM Corporation. * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause */ -#include "libfdt_env.h" +#include #ifndef USE_HOSTCC #include @@ -21,7 +21,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, int proplen; propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); - if (! propval) + if (!propval) return proplen; if (proplen != len) @@ -45,7 +45,7 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name) int len; prop = fdt_get_property_w(fdt, nodeoffset, name, &len); - if (! prop) + if (!prop) return len; _fdt_nop_region(prop, len + sizeof(*prop)); -- cgit v1.2.1 From 21047b31f1d7db585bbb58ae2b733e3987b23e61 Mon Sep 17 00:00:00 2001 From: "mario.six@gdsys.cc" Date: Wed, 25 May 2016 15:18:10 +0200 Subject: sandbox: gpio: doc: Fix parameter documentation The documentation of parameters in arch/sandbox/include/asm/gpio.h is either missing or faulty. This patch corrects the documentation. Signed-off-by: Mario Six Acked-by: Simon Glass --- arch/sandbox/include/asm/gpio.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/sandbox/include/asm/gpio.h b/arch/sandbox/include/asm/gpio.h index 427af2c970..73b42f0f08 100644 --- a/arch/sandbox/include/asm/gpio.h +++ b/arch/sandbox/include/asm/gpio.h @@ -26,7 +26,8 @@ /** * Return the simulated value of a GPIO (used only in sandbox test code) * - * @param gp GPIO number + * @param dev device to use + * @param offset GPIO offset within bank * @return -1 on error, 0 if GPIO is low, >0 if high */ int sandbox_gpio_get_value(struct udevice *dev, unsigned int offset); @@ -34,8 +35,9 @@ int sandbox_gpio_get_value(struct udevice *dev, unsigned int offset); /** * Set the simulated value of a GPIO (used only in sandbox test code) * - * @param gp GPIO number - * @param value value to set (0 for low, non-zero for high) + * @param dev device to use + * @param offset GPIO offset within bank + * @param value value to set (0 for low, non-zero for high) * @return -1 on error, 0 if ok */ int sandbox_gpio_set_value(struct udevice *dev, unsigned int offset, int value); @@ -63,7 +65,8 @@ int sandbox_gpio_get_open_drain(struct udevice *dev, unsigned offset); /** * Return the simulated direction of a GPIO (used only in sandbox test code) * - * @param gp GPIO number + * @param dev device to use + * @param offset GPIO offset within bank * @return -1 on error, 0 if GPIO is input, >0 if output */ int sandbox_gpio_get_direction(struct udevice *dev, unsigned int offset); @@ -71,8 +74,9 @@ int sandbox_gpio_get_direction(struct udevice *dev, unsigned int offset); /** * Set the simulated direction of a GPIO (used only in sandbox test code) * - * @param gp GPIO number - * @param output 0 to set as input, 1 to set as output + * @param dev device to use + * @param offset GPIO offset within bank + * @param output 0 to set as input, 1 to set as output * @return -1 on error, 0 if ok */ int sandbox_gpio_set_direction(struct udevice *dev, unsigned int offset, -- cgit v1.2.1 From 769d52ef0f04812fd65ef2f3ab921ad2e8562ab1 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 17 Jun 2016 09:43:56 -0600 Subject: mailbox: rename headers Rename mailbox*.h to match the naming convention requested during review of the new reset subsystem. Signed-off-by: Stephen Warren Acked-by: Simon Glass --- drivers/mailbox/mailbox-uclass.c | 4 +- drivers/mailbox/sandbox-mbox-test.c | 2 +- drivers/mailbox/sandbox-mbox.c | 2 +- include/mailbox-uclass.h | 83 ++++++++++++++++++++ include/mailbox.h | 149 ++++++++++++++++++++++++++++++++++++ include/mailbox_client.h | 149 ------------------------------------ include/mailbox_uclass.h | 83 -------------------- 7 files changed, 236 insertions(+), 236 deletions(-) create mode 100644 include/mailbox-uclass.h create mode 100644 include/mailbox.h delete mode 100644 include/mailbox_client.h delete mode 100644 include/mailbox_uclass.h diff --git a/drivers/mailbox/mailbox-uclass.c b/drivers/mailbox/mailbox-uclass.c index 73fa32874a..40f851d915 100644 --- a/drivers/mailbox/mailbox-uclass.c +++ b/drivers/mailbox/mailbox-uclass.c @@ -7,8 +7,8 @@ #include #include #include -#include -#include +#include +#include DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/mailbox/sandbox-mbox-test.c b/drivers/mailbox/sandbox-mbox-test.c index 02d161aada..8351522bd4 100644 --- a/drivers/mailbox/sandbox-mbox-test.c +++ b/drivers/mailbox/sandbox-mbox-test.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include struct sandbox_mbox_test { diff --git a/drivers/mailbox/sandbox-mbox.c b/drivers/mailbox/sandbox-mbox.c index 1b7ac231cb..530c62c029 100644 --- a/drivers/mailbox/sandbox-mbox.c +++ b/drivers/mailbox/sandbox-mbox.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/include/mailbox-uclass.h b/include/mailbox-uclass.h new file mode 100644 index 0000000000..6ec62e5a0e --- /dev/null +++ b/include/mailbox-uclass.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _MAILBOX_UCLASS_H +#define _MAILBOX_UCLASS_H + +/* See mailbox.h for background documentation. */ + +#include + +struct udevice; + +/** + * struct mbox_ops - The functions that a mailbox driver must implement. + */ +struct mbox_ops { + /** + * of_xlate - Translate a client's device-tree (OF) mailbox specifier. + * + * The mailbox core calls this function as the first step in + * implementing a client's mbox_get_by_*() call. + * + * If this function pointer is set to NULL, the mailbox core will use + * a default implementation, which assumes #mbox-cells = <1>, and that + * the DT cell contains a simple integer channel ID. + * + * At present, the mailbox API solely supports device-tree. If this + * changes, other xxx_xlate() functions may be added to support those + * other mechanisms. + * + * @chan: The channel to hold the translation result. + * @args: The mailbox specifier values from device tree. + * @return 0 if OK, or a negative error code. + */ + int (*of_xlate)(struct mbox_chan *chan, + struct fdtdec_phandle_args *args); + /** + * request - Request a translated channel. + * + * The mailbox core calls this function as the second step in + * implementing a client's mbox_get_by_*() call, following a successful + * xxx_xlate() call. + * + * @chan: The channel to request; this has been filled in by a + * previoux xxx_xlate() function call. + * @return 0 if OK, or a negative error code. + */ + int (*request)(struct mbox_chan *chan); + /** + * free - Free a previously requested channel. + * + * This is the implementation of the client mbox_free() API. + * + * @chan: The channel to free. + * @return 0 if OK, or a negative error code. + */ + int (*free)(struct mbox_chan *chan); + /** + * send - Send a message over a mailbox channel + * + * @chan: The channel to send to the message to. + * @data: A pointer to the message to send. + * @return 0 if OK, or a negative error code. + */ + int (*send)(struct mbox_chan *chan, const void *data); + /** + * recv - Receive any available message from the channel. + * + * This function does not block. If not message is immediately + * available, the function should return an error. + * + * @chan: The channel to receive to the message from. + * @data: A pointer to the buffer to hold the received message. + * @return 0 if OK, -ENODATA if no message was available, or a negative + * error code. + */ + int (*recv)(struct mbox_chan *chan, void *data); +}; + +#endif diff --git a/include/mailbox.h b/include/mailbox.h new file mode 100644 index 0000000000..a92a1a590d --- /dev/null +++ b/include/mailbox.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _MAILBOX_H +#define _MAILBOX_H + +/** + * A mailbox is a hardware mechanism for transferring small fixed-size messages + * and/or notifications between the CPU on which U-Boot runs and some other + * device such as an auxiliary CPU running firmware or a hardware module. + * + * Data transfer is optional; a mailbox may consist solely of a notification + * mechanism. When data transfer is implemented, it is via HW registers or + * FIFOs, rather than via RAM-based buffers. The mailbox API generally + * implements any communication protocol enforced solely by hardware, and + * leaves any higher-level protocols to other layers. + * + * A mailbox channel is a bi-directional mechanism that can send a message or + * notification to a single specific remote entity, and receive messages or + * notifications from that entity. The size, content, and format of such + * messages is defined by the mailbox implementation, or the remote entity with + * which it communicates; there is no general standard at this API level. + * + * A driver that implements UCLASS_MAILBOX is a mailbox provider. A provider + * will often implement multiple separate mailbox channels, since the hardware + * it manages often has this capability. mailbox-uclass.h describes the + * interface which mailbox providers must implement. + * + * Mailbox consumers/clients generate and send, or receive and process, + * messages. This header file describes the API used by clients. + */ + +struct udevice; + +/** + * struct mbox_chan - A handle to a single mailbox channel. + * + * Clients provide storage for channels. The content of the channel structure + * is managed solely by the mailbox API and mailbox drivers. A mailbox channel + * is initialized by "get"ing the mailbox. The channel struct is passed to all + * other mailbox APIs to identify which mailbox to operate upon. + * + * @dev: The device which implements the mailbox. + * @id: The mailbox channel ID within the provider. + * + * Currently, the mailbox API assumes that a single integer ID is enough to + * identify and configure any mailbox channel for any mailbox provider. If this + * assumption becomes invalid in the future, the struct could be expanded to + * either (a) add more fields to allow mailbox providers to store additional + * information, or (b) replace the id field with an opaque pointer, which the + * provider would dynamically allocated during its .of_xlate op, and process + * during is .request op. This may require the addition of an extra op to clean + * up the allocation. + */ +struct mbox_chan { + struct udevice *dev; + /* + * Written by of_xlate. We assume a single id is enough for now. In the + * future, we might add more fields here. + */ + unsigned long id; +}; + +/** + * mbox_get_by_index - Get/request a mailbox by integer index + * + * This looks up and requests a mailbox channel. The index is relative to the + * client device; each device is assumed to have n mailbox channels associated + * with it somehow, and this function finds and requests one of them. The + * mapping of client device channel indices to provider channels may be via + * device-tree properties, board-provided mapping tables, or some other + * mechanism. + * + * @dev: The client device. + * @index: The index of the mailbox channel to request, within the + * client's list of channels. + * @chan A pointer to a channel object to initialize. + * @return 0 if OK, or a negative error code. + */ +int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan); + +/** + * mbox_get_by_name - Get/request a mailbox by name + * + * This looks up and requests a mailbox channel. The name is relative to the + * client device; each device is assumed to have n mailbox channels associated + * with it somehow, and this function finds and requests one of them. The + * mapping of client device channel names to provider channels may be via + * device-tree properties, board-provided mapping tables, or some other + * mechanism. + * + * @dev: The client device. + * @name: The name of the mailbox channel to request, within the client's + * list of channels. + * @chan A pointer to a channel object to initialize. + * @return 0 if OK, or a negative error code. + */ +int mbox_get_by_name(struct udevice *dev, const char *name, + struct mbox_chan *chan); + +/** + * mbox_free - Free a previously requested mailbox channel. + * + * @chan: A channel object that was previously successfully requested by + * calling mbox_get_by_*(). + * @return 0 if OK, or a negative error code. + */ +int mbox_free(struct mbox_chan *chan); + +/** + * mbox_send - Send a message over a mailbox channel + * + * This function will send a message to the remote entity. It may return before + * the remote entity has received and/or processed the message. + * + * @chan: A channel object that was previously successfully requested by + * calling mbox_get_by_*(). + * @data: A pointer to the message to transfer. The format and size of + * the memory region pointed at by @data is determined by the + * mailbox provider. Providers that solely transfer notifications + * will ignore this parameter. + * @return 0 if OK, or a negative error code. + */ +int mbox_send(struct mbox_chan *chan, const void *data); + +/** + * mbox_recv - Receive any available message from a mailbox channel + * + * This function will wait (up to the specified @timeout_us) for a message to + * be sent by the remote entity, and write the content of any such message + * into a caller-provided buffer. + * + * @chan: A channel object that was previously successfully requested by + * calling mbox_get_by_*(). + * @data: A pointer to the buffer to receive the message. The format and + * size of the memory region pointed at by @data is determined by + * the mailbox provider. Providers that solely transfer + * notifications will ignore this parameter. + * @timeout_us: The maximum time to wait for a message to be available, in + * micro-seconds. A value of 0 does not wait at all. + * @return 0 if OK, -ENODATA if no message was available, or a negative error + * code. + */ +int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us); + +#endif diff --git a/include/mailbox_client.h b/include/mailbox_client.h deleted file mode 100644 index 8345ea0bf1..0000000000 --- a/include/mailbox_client.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2016, NVIDIA CORPORATION. - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#ifndef _MAILBOX_CLIENT_H -#define _MAILBOX_CLIENT_H - -/** - * A mailbox is a hardware mechanism for transferring small fixed-size messages - * and/or notifications between the CPU on which U-Boot runs and some other - * device such as an auxiliary CPU running firmware or a hardware module. - * - * Data transfer is optional; a mailbox may consist solely of a notification - * mechanism. When data transfer is implemented, it is via HW registers or - * FIFOs, rather than via RAM-based buffers. The mailbox API generally - * implements any communication protocol enforced solely by hardware, and - * leaves any higher-level protocols to other layers. - * - * A mailbox channel is a bi-directional mechanism that can send a message or - * notification to a single specific remote entity, and receive messages or - * notifications from that entity. The size, content, and format of such - * messages is defined by the mailbox implementation, or the remote entity with - * which it communicates; there is no general standard at this API level. - * - * A driver that implements UCLASS_MAILBOX is a mailbox provider. A provider - * will often implement multiple separate mailbox channels, since the hardware - * it manages often has this capability. mailbox_uclass.h describes the - * interface which mailbox providers must implement. - * - * Mailbox consumers/clients generate and send, or receive and process, - * messages. This header file describes the API used by clients. - */ - -struct udevice; - -/** - * struct mbox_chan - A handle to a single mailbox channel. - * - * Clients provide storage for channels. The content of the channel structure - * is managed solely by the mailbox API and mailbox drivers. A mailbox channel - * is initialized by "get"ing the mailbox. The channel struct is passed to all - * other mailbox APIs to identify which mailbox to operate upon. - * - * @dev: The device which implements the mailbox. - * @id: The mailbox channel ID within the provider. - * - * Currently, the mailbox API assumes that a single integer ID is enough to - * identify and configure any mailbox channel for any mailbox provider. If this - * assumption becomes invalid in the future, the struct could be expanded to - * either (a) add more fields to allow mailbox providers to store additional - * information, or (b) replace the id field with an opaque pointer, which the - * provider would dynamically allocated during its .of_xlate op, and process - * during is .request op. This may require the addition of an extra op to clean - * up the allocation. - */ -struct mbox_chan { - struct udevice *dev; - /* - * Written by of_xlate. We assume a single id is enough for now. In the - * future, we might add more fields here. - */ - unsigned long id; -}; - -/** - * mbox_get_by_index - Get/request a mailbox by integer index - * - * This looks up and requests a mailbox channel. The index is relative to the - * client device; each device is assumed to have n mailbox channels associated - * with it somehow, and this function finds and requests one of them. The - * mapping of client device channel indices to provider channels may be via - * device-tree properties, board-provided mapping tables, or some other - * mechanism. - * - * @dev: The client device. - * @index: The index of the mailbox channel to request, within the - * client's list of channels. - * @chan A pointer to a channel object to initialize. - * @return 0 if OK, or a negative error code. - */ -int mbox_get_by_index(struct udevice *dev, int index, struct mbox_chan *chan); - -/** - * mbox_get_by_name - Get/request a mailbox by name - * - * This looks up and requests a mailbox channel. The name is relative to the - * client device; each device is assumed to have n mailbox channels associated - * with it somehow, and this function finds and requests one of them. The - * mapping of client device channel names to provider channels may be via - * device-tree properties, board-provided mapping tables, or some other - * mechanism. - * - * @dev: The client device. - * @name: The name of the mailbox channel to request, within the client's - * list of channels. - * @chan A pointer to a channel object to initialize. - * @return 0 if OK, or a negative error code. - */ -int mbox_get_by_name(struct udevice *dev, const char *name, - struct mbox_chan *chan); - -/** - * mbox_free - Free a previously requested mailbox channel. - * - * @chan: A channel object that was previously successfully requested by - * calling mbox_get_by_*(). - * @return 0 if OK, or a negative error code. - */ -int mbox_free(struct mbox_chan *chan); - -/** - * mbox_send - Send a message over a mailbox channel - * - * This function will send a message to the remote entity. It may return before - * the remote entity has received and/or processed the message. - * - * @chan: A channel object that was previously successfully requested by - * calling mbox_get_by_*(). - * @data: A pointer to the message to transfer. The format and size of - * the memory region pointed at by @data is determined by the - * mailbox provider. Providers that solely transfer notifications - * will ignore this parameter. - * @return 0 if OK, or a negative error code. - */ -int mbox_send(struct mbox_chan *chan, const void *data); - -/** - * mbox_recv - Receive any available message from a mailbox channel - * - * This function will wait (up to the specified @timeout_us) for a message to - * be sent by the remote entity, and write the content of any such message - * into a caller-provided buffer. - * - * @chan: A channel object that was previously successfully requested by - * calling mbox_get_by_*(). - * @data: A pointer to the buffer to receive the message. The format and - * size of the memory region pointed at by @data is determined by - * the mailbox provider. Providers that solely transfer - * notifications will ignore this parameter. - * @timeout_us: The maximum time to wait for a message to be available, in - * micro-seconds. A value of 0 does not wait at all. - * @return 0 if OK, -ENODATA if no message was available, or a negative error - * code. - */ -int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us); - -#endif diff --git a/include/mailbox_uclass.h b/include/mailbox_uclass.h deleted file mode 100644 index 6a2994c34c..0000000000 --- a/include/mailbox_uclass.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2016, NVIDIA CORPORATION. - * - * SPDX-License-Identifier: GPL-2.0 - */ - -#ifndef _MAILBOX_UCLASS_H -#define _MAILBOX_UCLASS_H - -/* See mailbox_client.h for background documentation. */ - -#include - -struct udevice; - -/** - * struct mbox_ops - The functions that a mailbox driver must implement. - */ -struct mbox_ops { - /** - * of_xlate - Translate a client's device-tree (OF) mailbox specifier. - * - * The mailbox core calls this function as the first step in - * implementing a client's mbox_get_by_*() call. - * - * If this function pointer is set to NULL, the mailbox core will use - * a default implementation, which assumes #mbox-cells = <1>, and that - * the DT cell contains a simple integer channel ID. - * - * At present, the mailbox API solely supports device-tree. If this - * changes, other xxx_xlate() functions may be added to support those - * other mechanisms. - * - * @chan: The channel to hold the translation result. - * @args: The mailbox specifier values from device tree. - * @return 0 if OK, or a negative error code. - */ - int (*of_xlate)(struct mbox_chan *chan, - struct fdtdec_phandle_args *args); - /** - * request - Request a translated channel. - * - * The mailbox core calls this function as the second step in - * implementing a client's mbox_get_by_*() call, following a successful - * xxx_xlate() call. - * - * @chan: The channel to request; this has been filled in by a - * previoux xxx_xlate() function call. - * @return 0 if OK, or a negative error code. - */ - int (*request)(struct mbox_chan *chan); - /** - * free - Free a previously requested channel. - * - * This is the implementation of the client mbox_free() API. - * - * @chan: The channel to free. - * @return 0 if OK, or a negative error code. - */ - int (*free)(struct mbox_chan *chan); - /** - * send - Send a message over a mailbox channel - * - * @chan: The channel to send to the message to. - * @data: A pointer to the message to send. - * @return 0 if OK, or a negative error code. - */ - int (*send)(struct mbox_chan *chan, const void *data); - /** - * recv - Receive any available message from the channel. - * - * This function does not block. If not message is immediately - * available, the function should return an error. - * - * @chan: The channel to receive to the message from. - * @data: A pointer to the buffer to hold the received message. - * @return 0 if OK, -ENODATA if no message was available, or a negative - * error code. - */ - int (*recv)(struct mbox_chan *chan, void *data); -}; - -#endif -- cgit v1.2.1 From 0f67e2395be44db2c1bef17b6ada2e46221908ed Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 17 Jun 2016 09:43:57 -0600 Subject: mailbox: add Tegra186 HSP driver Tegra186's HSP module implements doorbells, mailboxes, semaphores, and shared interrupts. This patch provides a driver for HSP, and hooks it into the mailbox API. Currently, only doorbells are supported. Signed-off-by: Stephen Warren Reviewed-by: Simon Glass Acked-by: Simon Glass --- arch/arm/dts/tegra186.dtsi | 13 +++ arch/arm/mach-tegra/Kconfig | 2 + drivers/mailbox/Kconfig | 7 ++ drivers/mailbox/Makefile | 1 + drivers/mailbox/tegra-hsp.c | 163 ++++++++++++++++++++++++++++++++ include/dt-bindings/mailbox/tegra-hsp.h | 14 +++ 6 files changed, 200 insertions(+) create mode 100644 drivers/mailbox/tegra-hsp.c create mode 100644 include/dt-bindings/mailbox/tegra-hsp.h diff --git a/arch/arm/dts/tegra186.dtsi b/arch/arm/dts/tegra186.dtsi index 18b6a26643..fce34fa650 100644 --- a/arch/arm/dts/tegra186.dtsi +++ b/arch/arm/dts/tegra186.dtsi @@ -1,6 +1,7 @@ #include "skeleton.dtsi" #include #include +#include / { compatible = "nvidia,tegra186"; @@ -40,6 +41,18 @@ status = "disabled"; }; + hsp: hsp@3c00000 { + compatible = "nvidia,tegra186-hsp"; + reg = <0x0 0x03c00000 0x0 0xa0000>; + interrupts = ; + nvidia,num-SM = <0x8>; + nvidia,num-AS = <0x2>; + nvidia,num-SS = <0x2>; + nvidia,num-DB = <0x7>; + nvidia,num-SI = <0x8>; + #mbox-cells = <1>; + }; + gpio@c2f0000 { compatible = "nvidia,tegra186-gpio-aon"; reg-names = "security", "gpio"; diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index b18a12e342..f4affa5512 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -56,8 +56,10 @@ config TEGRA210 config TEGRA186 bool "Tegra186 family" + select DM_MAILBOX select TEGRA186_GPIO select TEGRA_ARMV8_COMMON + select TEGRA_HSP endchoice diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 9087512390..9649b70589 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -17,4 +17,11 @@ config SANDBOX_MBOX Enable support for a test mailbox implementation, which simply echos back a modified version of any message that is sent. +config TEGRA_HSP + bool "Enable Tegra HSP controller support" + depends on DM_MAILBOX && TEGRA + help + This enables support for the NVIDIA Tegra HSP Hw module, which + implements doorbells, mailboxes, semaphores, and shared interrupts. + endmenu diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index bbae4def6d..155dbeb099 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_DM_MAILBOX) += mailbox-uclass.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o +obj-$(CONFIG_TEGRA_HSP) += tegra-hsp.o diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c new file mode 100644 index 0000000000..5c781a50b6 --- /dev/null +++ b/drivers/mailbox/tegra-hsp.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#define TEGRA_HSP_DB_REG_TRIGGER 0x0 +#define TEGRA_HSP_DB_REG_ENABLE 0x4 +#define TEGRA_HSP_DB_REG_RAW 0x8 +#define TEGRA_HSP_DB_REG_PENDING 0xc + +#define TEGRA_HSP_DB_ID_CCPLEX 1 +#define TEGRA_HSP_DB_ID_BPMP 3 +#define TEGRA_HSP_DB_ID_NUM 7 + +struct tegra_hsp { + fdt_addr_t regs; + uint32_t db_base; +}; + +DECLARE_GLOBAL_DATA_PTR; + +static uint32_t *tegra_hsp_reg(struct tegra_hsp *thsp, uint32_t db_id, + uint32_t reg) +{ + return (uint32_t *)(thsp->regs + thsp->db_base + (db_id * 0x100) + reg); +} + +static uint32_t tegra_hsp_readl(struct tegra_hsp *thsp, uint32_t db_id, + uint32_t reg) +{ + uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); + return readl(r); +} + +static void tegra_hsp_writel(struct tegra_hsp *thsp, uint32_t val, + uint32_t db_id, uint32_t reg) +{ + uint32_t *r = tegra_hsp_reg(thsp, db_id, reg); + + writel(val, r); + readl(r); +} + +static int tegra_hsp_db_id(ulong chan_id) +{ + switch (chan_id) { + case TEGRA_HSP_MASTER_BPMP: + return TEGRA_HSP_DB_ID_BPMP; + default: + debug("Invalid channel ID\n"); + return -EINVAL; + } +} + +static int tegra_hsp_request(struct mbox_chan *chan) +{ + int db_id; + + debug("%s(chan=%p)\n", __func__, chan); + + db_id = tegra_hsp_db_id(chan->id); + if (db_id < 0) { + debug("tegra_hsp_db_id() failed: %d\n", db_id); + return -EINVAL; + } + + return 0; +} + +static int tegra_hsp_free(struct mbox_chan *chan) +{ + debug("%s(chan=%p)\n", __func__, chan); + + return 0; +} + +static int tegra_hsp_send(struct mbox_chan *chan, const void *data) +{ + struct tegra_hsp *thsp = dev_get_priv(chan->dev); + int db_id; + + debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + + db_id = tegra_hsp_db_id(chan->id); + tegra_hsp_writel(thsp, 1, db_id, TEGRA_HSP_DB_REG_TRIGGER); + + return 0; +} + +static int tegra_hsp_recv(struct mbox_chan *chan, void *data) +{ + struct tegra_hsp *thsp = dev_get_priv(chan->dev); + uint32_t db_id = TEGRA_HSP_DB_ID_CCPLEX; + uint32_t val; + + debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + + val = tegra_hsp_readl(thsp, db_id, TEGRA_HSP_DB_REG_RAW); + if (!(val & BIT(chan->id))) + return -ENODATA; + + tegra_hsp_writel(thsp, BIT(chan->id), db_id, TEGRA_HSP_DB_REG_RAW); + + return 0; +} + +static int tegra_hsp_bind(struct udevice *dev) +{ + debug("%s(dev=%p)\n", __func__, dev); + + return 0; +} + +static int tegra_hsp_probe(struct udevice *dev) +{ + struct tegra_hsp *thsp = dev_get_priv(dev); + int nr_sm, nr_ss, nr_as; + + debug("%s(dev=%p)\n", __func__, dev); + + thsp->regs = dev_get_addr(dev); + if (thsp->regs == FDT_ADDR_T_NONE) + return -ENODEV; + + nr_sm = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "nvidia,num-SM", + 0); + nr_ss = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "nvidia,num-SS", + 0); + nr_as = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "nvidia,num-AS", + 0); + thsp->db_base = (1 + (nr_sm >> 1) + nr_ss + nr_as) << 16; + + return 0; +} + +static const struct udevice_id tegra_hsp_ids[] = { + { .compatible = "nvidia,tegra186-hsp" }, + { } +}; + +struct mbox_ops tegra_hsp_mbox_ops = { + .request = tegra_hsp_request, + .free = tegra_hsp_free, + .send = tegra_hsp_send, + .recv = tegra_hsp_recv, +}; + +U_BOOT_DRIVER(tegra_hsp) = { + .name = "tegra-hsp", + .id = UCLASS_MAILBOX, + .of_match = tegra_hsp_ids, + .bind = tegra_hsp_bind, + .probe = tegra_hsp_probe, + .priv_auto_alloc_size = sizeof(struct tegra_hsp), + .ops = &tegra_hsp_mbox_ops, +}; diff --git a/include/dt-bindings/mailbox/tegra-hsp.h b/include/dt-bindings/mailbox/tegra-hsp.h new file mode 100644 index 0000000000..e8c23fa91d --- /dev/null +++ b/include/dt-bindings/mailbox/tegra-hsp.h @@ -0,0 +1,14 @@ +/* + * This header provides constants for binding nvidia,tegra186-hsp. + * + * The number with TEGRA_HSP_MASTER prefix indicates the bit that is + * associated with a master ID in the doorbell registers. + */ + +#ifndef _DT_BINDINGS_MAILBOX_TEGRA186_HSP_H +#define _DT_BINDINGS_MAILBOX_TEGRA186_HSP_H + +#define TEGRA_HSP_MASTER_CCPLEX 17 +#define TEGRA_HSP_MASTER_BPMP 19 + +#endif -- cgit v1.2.1 From 89c1e2da78f82a09685006291ce8bb44f635fa25 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 17 Jun 2016 09:43:58 -0600 Subject: Add a reset driver framework/uclass A reset controller is a hardware module that controls reset signals that affect other hardware modules or chips. This patch defines a standard API that connects reset clients (i.e. the drivers for devices affected by reset signals) to drivers for reset controllers/providers. Initially, DT is the only supported method for connecting the two. The DT binding specification (reset.txt) was taken from Linux kernel v4.5's Documentation/devicetree/bindings/reset/reset.txt. Signed-off-by: Stephen Warren Acked-by: Simon Glass --- doc/device-tree-bindings/reset/reset.txt | 75 +++++++++++++++++ drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/reset/Kconfig | 15 ++++ drivers/reset/Makefile | 5 ++ drivers/reset/reset-uclass.c | 131 ++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/reset-uclass.h | 81 +++++++++++++++++++ include/reset.h | 135 +++++++++++++++++++++++++++++++ 9 files changed, 446 insertions(+) create mode 100644 doc/device-tree-bindings/reset/reset.txt create mode 100644 drivers/reset/Kconfig create mode 100644 drivers/reset/Makefile create mode 100644 drivers/reset/reset-uclass.c create mode 100644 include/reset-uclass.h create mode 100644 include/reset.h diff --git a/doc/device-tree-bindings/reset/reset.txt b/doc/device-tree-bindings/reset/reset.txt new file mode 100644 index 0000000000..31db6ff849 --- /dev/null +++ b/doc/device-tree-bindings/reset/reset.txt @@ -0,0 +1,75 @@ += Reset Signal Device Tree Bindings = + +This binding is intended to represent the hardware reset signals present +internally in most IC (SoC, FPGA, ...) designs. Reset signals for whole +standalone chips are most likely better represented as GPIOs, although there +are likely to be exceptions to this rule. + +Hardware blocks typically receive a reset signal. This signal is generated by +a reset provider (e.g. power management or clock module) and received by a +reset consumer (the module being reset, or a module managing when a sub- +ordinate module is reset). This binding exists to represent the provider and +consumer, and provide a way to couple the two together. + +A reset signal is represented by the phandle of the provider, plus a reset +specifier - a list of DT cells that represents the reset signal within the +provider. The length (number of cells) and semantics of the reset specifier +are dictated by the binding of the reset provider, although common schemes +are described below. + +A word on where to place reset signal consumers in device tree: It is possible +in hardware for a reset signal to affect multiple logically separate HW blocks +at once. In this case, it would be unwise to represent this reset signal in +the DT node of each affected HW block, since if activated, an unrelated block +may be reset. Instead, reset signals should be represented in the DT node +where it makes most sense to control it; this may be a bus node if all +children of the bus are affected by the reset signal, or an individual HW +block node for dedicated reset signals. The intent of this binding is to give +appropriate software access to the reset signals in order to manage the HW, +rather than to slavishly enumerate the reset signal that affects each HW +block. + += Reset providers = + +Required properties: +#reset-cells: Number of cells in a reset specifier; Typically 0 for nodes + with a single reset output and 1 for nodes with multiple + reset outputs. + +For example: + + rst: reset-controller { + #reset-cells = <1>; + }; + += Reset consumers = + +Required properties: +resets: List of phandle and reset specifier pairs, one pair + for each reset signal that affects the device, or that the + device manages. Note: if the reset provider specifies '0' for + #reset-cells, then only the phandle portion of the pair will + appear. + +Optional properties: +reset-names: List of reset signal name strings sorted in the same order as + the resets property. Consumers drivers will use reset-names to + match reset signal names with reset specifiers. + +For example: + + device { + resets = <&rst 20>; + reset-names = "reset"; + }; + +This represents a device with a single reset signal named "reset". + + bus { + resets = <&rst 10> <&rst 11> <&rst 12> <&rst 11>; + reset-names = "i2s1", "i2s2", "dma", "mixer"; + }; + +This represents a bus that controls the reset signal of each of four sub- +ordinate devices. Consider for example a bus that fails to operate unless no +child device has reset asserted. diff --git a/drivers/Kconfig b/drivers/Kconfig index f2a137ad87..f6003a0a59 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -56,6 +56,8 @@ source "drivers/ram/Kconfig" source "drivers/remoteproc/Kconfig" +source "drivers/reset/Kconfig" + source "drivers/rtc/Kconfig" source "drivers/serial/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index db5317c9c7..1723958857 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_U_QE) += qe/ obj-y += mailbox/ obj-y += memory/ obj-y += pwm/ +obj-y += reset/ obj-y += input/ # SOC specific infrastructure drivers. obj-y += soc/ diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig new file mode 100644 index 0000000000..5c449a99d3 --- /dev/null +++ b/drivers/reset/Kconfig @@ -0,0 +1,15 @@ +menu "Reset Controller Support" + +config DM_RESET + bool "Enable reset controllers using Driver Model" + depends on DM && OF_CONTROL + help + Enable support for the reset controller driver class. Many hardware + modules are equipped with a reset signal, typically driven by some + reset controller hardware module within the chip. In U-Boot, reset + controller drivers allow control over these reset signals. In some + cases this API is applicable to chips outside the CPU as well, + although driving such reset isgnals using GPIOs may be more + appropriate in this case. + +endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile new file mode 100644 index 0000000000..508608e83f --- /dev/null +++ b/drivers/reset/Makefile @@ -0,0 +1,5 @@ +# Copyright (c) 2016, NVIDIA CORPORATION. +# +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_DM_RESET) += reset-uclass.o diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c new file mode 100644 index 0000000000..edaecfbc99 --- /dev/null +++ b/drivers/reset/reset-uclass.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static inline struct reset_ops *reset_dev_ops(struct udevice *dev) +{ + return (struct reset_ops *)dev->driver->ops; +} + +static int reset_of_xlate_default(struct reset_ctl *reset_ctl, + struct fdtdec_phandle_args *args) +{ + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + + if (args->args_count != 1) { + debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } + + reset_ctl->id = args->args[0]; + + return 0; +} + +int reset_get_by_index(struct udevice *dev, int index, + struct reset_ctl *reset_ctl) +{ + struct fdtdec_phandle_args args; + int ret; + struct udevice *dev_reset; + struct reset_ops *ops; + + debug("%s(dev=%p, index=%d, reset_ctl=%p)\n", __func__, dev, index, + reset_ctl); + + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, + "resets", "#reset-cells", 0, + index, &args); + if (ret) { + debug("%s: fdtdec_parse_phandle_with_args failed: %d\n", + __func__, ret); + return ret; + } + + ret = uclass_get_device_by_of_offset(UCLASS_RESET, args.node, + &dev_reset); + if (ret) { + debug("%s: uclass_get_device_by_of_offset failed: %d\n", + __func__, ret); + return ret; + } + ops = reset_dev_ops(dev_reset); + + reset_ctl->dev = dev_reset; + if (ops->of_xlate) + ret = ops->of_xlate(reset_ctl, &args); + else + ret = reset_of_xlate_default(reset_ctl, &args); + if (ret) { + debug("of_xlate() failed: %d\n", ret); + return ret; + } + + ret = ops->request(reset_ctl); + if (ret) { + debug("ops->request() failed: %d\n", ret); + return ret; + } + + return 0; +} + +int reset_get_by_name(struct udevice *dev, const char *name, + struct reset_ctl *reset_ctl) +{ + int index; + + debug("%s(dev=%p, name=%s, reset_ctl=%p)\n", __func__, dev, name, + reset_ctl); + + index = fdt_find_string(gd->fdt_blob, dev->of_offset, "reset-names", + name); + if (index < 0) { + debug("fdt_find_string() failed: %d\n", index); + return index; + } + + return reset_get_by_index(dev, index, reset_ctl); +} + +int reset_free(struct reset_ctl *reset_ctl) +{ + struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); + + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + + return ops->free(reset_ctl); +} + +int reset_assert(struct reset_ctl *reset_ctl) +{ + struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); + + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + + return ops->rst_assert(reset_ctl); +} + +int reset_deassert(struct reset_ctl *reset_ctl) +{ + struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); + + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + + return ops->rst_deassert(reset_ctl); +} + +UCLASS_DRIVER(reset) = { + .id = UCLASS_RESET, + .name = "reset", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 0777cbe27e..b768660e85 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -63,6 +63,7 @@ enum uclass_id { UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_REGULATOR, /* Regulator device */ UCLASS_REMOTEPROC, /* Remote Processor device */ + UCLASS_RESET, /* Reset controller device */ UCLASS_RTC, /* Real time clock device */ UCLASS_SERIAL, /* Serial UART */ UCLASS_SPI, /* SPI bus */ diff --git a/include/reset-uclass.h b/include/reset-uclass.h new file mode 100644 index 0000000000..50adeca757 --- /dev/null +++ b/include/reset-uclass.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _RESET_UCLASS_H +#define _RESET_UCLASS_H + +/* See reset.h for background documentation. */ + +#include + +struct udevice; + +/** + * struct reset_ops - The functions that a reset controller driver must + * implement. + */ +struct reset_ops { + /** + * of_xlate - Translate a client's device-tree (OF) reset specifier. + * + * The reset core calls this function as the first step in implementing + * a client's reset_get_by_*() call. + * + * If this function pointer is set to NULL, the reset core will use a + * default implementation, which assumes #reset-cells = <1>, and that + * the DT cell contains a simple integer reset signal ID. + * + * At present, the reset API solely supports device-tree. If this + * changes, other xxx_xlate() functions may be added to support those + * other mechanisms. + * + * @reset_ctl: The reset control struct to hold the translation result. + * @args: The reset specifier values from device tree. + * @return 0 if OK, or a negative error code. + */ + int (*of_xlate)(struct reset_ctl *reset_ctl, + struct fdtdec_phandle_args *args); + /** + * request - Request a translated reset control. + * + * The reset core calls this function as the second step in + * implementing a client's reset_get_by_*() call, following a + * successful xxx_xlate() call. + * + * @reset_ctl: The reset control struct to request; this has been + * filled in by a previoux xxx_xlate() function call. + * @return 0 if OK, or a negative error code. + */ + int (*request)(struct reset_ctl *reset_ctl); + /** + * free - Free a previously requested reset control. + * + * This is the implementation of the client reset_free() API. + * + * @reset_ctl: The reset control to free. + * @return 0 if OK, or a negative error code. + */ + int (*free)(struct reset_ctl *reset_ctl); + /** + * rst_assert - Assert a reset signal. + * + * Note: This function is named rst_assert not assert to avoid + * conflicting with global macro assert(). + * + * @reset_ctl: The reset signal to assert. + * @return 0 if OK, or a negative error code. + */ + int (*rst_assert)(struct reset_ctl *reset_ctl); + /** + * rst_deassert - Deassert a reset signal. + * + * @reset_ctl: The reset signal to deassert. + * @return 0 if OK, or a negative error code. + */ + int (*rst_deassert)(struct reset_ctl *reset_ctl); +}; + +#endif diff --git a/include/reset.h b/include/reset.h new file mode 100644 index 0000000000..dc0900f96a --- /dev/null +++ b/include/reset.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _RESET_H +#define _RESET_H + +/** + * A reset is a hardware signal indicating that a HW module (or IP block, or + * sometimes an entire off-CPU chip) reset all of its internal state to some + * known-good initial state. Drivers will often reset HW modules when they + * begin execution to ensure that hardware correctly responds to all requests, + * or in response to some error condition. Reset signals are often controlled + * externally to the HW module being reset, by an entity this API calls a reset + * controller. This API provides a standard means for drivers to request that + * reset controllers set or clear reset signals. + * + * A driver that implements UCLASS_RESET is a reset controller or provider. A + * controller will often implement multiple separate reset signals, since the + * hardware it manages often has this capability. reset-uclass.h describes the + * interface which reset controllers must implement. + * + * Reset consumers/clients are the HW modules affected by reset signals. This + * header file describes the API used by drivers for those HW modules. + */ + +struct udevice; + +/** + * struct reset_ctl - A handle to (allowing control of) a single reset signal. + * + * Clients provide storage for reset control handles. The content of the + * structure is managed solely by the reset API and reset drivers. A reset + * control struct is initialized by "get"ing the reset control struct. The + * reset control struct is passed to all other reset APIs to identify which + * reset signal to operate upon. + * + * @dev: The device which implements the reset signal. + * @id: The reset signal ID within the provider. + * + * Currently, the reset API assumes that a single integer ID is enough to + * identify and configure any reset signal for any reset provider. If this + * assumption becomes invalid in the future, the struct could be expanded to + * either (a) add more fields to allow reset providers to store additional + * information, or (b) replace the id field with an opaque pointer, which the + * provider would dynamically allocated during its .of_xlate op, and process + * during is .request op. This may require the addition of an extra op to clean + * up the allocation. + */ +struct reset_ctl { + struct udevice *dev; + /* + * Written by of_xlate. We assume a single id is enough for now. In the + * future, we might add more fields here. + */ + unsigned long id; +}; + +/** + * reset_get_by_index - Get/request a reset signal by integer index. + * + * This looks up and requests a reset signal. The index is relative to the + * client device; each device is assumed to have n reset signals associated + * with it somehow, and this function finds and requests one of them. The + * mapping of client device reset signal indices to provider reset signals may + * be via device-tree properties, board-provided mapping tables, or some other + * mechanism. + * + * @dev: The client device. + * @index: The index of the reset signal to request, within the client's + * list of reset signals. + * @reset_ctl A pointer to a reset control struct to initialize. + * @return 0 if OK, or a negative error code. + */ +int reset_get_by_index(struct udevice *dev, int index, + struct reset_ctl *reset_ctl); + +/** + * reset_get_by_name - Get/request a reset signal by name. + * + * This looks up and requests a reset signal. The name is relative to the + * client device; each device is assumed to have n reset signals associated + * with it somehow, and this function finds and requests one of them. The + * mapping of client device reset signal names to provider reset signal may be + * via device-tree properties, board-provided mapping tables, or some other + * mechanism. + * + * @dev: The client device. + * @name: The name of the reset signal to request, within the client's + * list of reset signals. + * @reset_ctl: A pointer to a reset control struct to initialize. + * @return 0 if OK, or a negative error code. + */ +int reset_get_by_name(struct udevice *dev, const char *name, + struct reset_ctl *reset_ctl); + +/** + * reset_free - Free a previously requested reset signal. + * + * @reset_ctl: A reset control struct that was previously successfully + * requested by reset_get_by_*(). + * @return 0 if OK, or a negative error code. + */ +int reset_free(struct reset_ctl *reset_ctl); + +/** + * reset_assert - Assert a reset signal. + * + * This function will assert the specified reset signal, thus resetting the + * affected HW module(s). Depending on the reset controller hardware, the reset + * signal will either stay asserted until reset_deassert() is called, or the + * hardware may autonomously clear the reset signal itself. + * + * @reset_ctl: A reset control struct that was previously successfully + * requested by reset_get_by_*(). + * @return 0 if OK, or a negative error code. + */ +int reset_assert(struct reset_ctl *reset_ctl); + +/** + * reset_deassert - Deassert a reset signal. + * + * This function will deassert the specified reset signal, thus releasing the + * affected HW modules() from reset, and allowing them to continue normal + * operation. + * + * @reset_ctl: A reset control struct that was previously successfully + * requested by reset_get_by_*(). + * @return 0 if OK, or a negative error code. + */ +int reset_deassert(struct reset_ctl *reset_ctl); + +#endif -- cgit v1.2.1 From 4581b717b1bf0fb04e7d9fcaf3d4c23d357154ac Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 17 Jun 2016 09:43:59 -0600 Subject: reset: implement a reset test This adds a sandbox reset implementation (provider), a test client device, instantiates them both from Sandbox's DT, and adds a DM test that excercises everything. Signed-off-by: Stephen Warren Acked-by: Simon Glass --- arch/sandbox/dts/test.dts | 11 ++++ arch/sandbox/include/asm/reset.h | 21 ++++++++ configs/sandbox_defconfig | 10 ++-- drivers/reset/Kconfig | 8 +++ drivers/reset/Makefile | 2 + drivers/reset/sandbox-reset-test.c | 55 +++++++++++++++++++ drivers/reset/sandbox-reset.c | 108 +++++++++++++++++++++++++++++++++++++ test/dm/Makefile | 1 + test/dm/reset.c | 39 ++++++++++++++ 9 files changed, 251 insertions(+), 4 deletions(-) create mode 100644 arch/sandbox/include/asm/reset.h create mode 100644 drivers/reset/sandbox-reset-test.c create mode 100644 drivers/reset/sandbox-reset.c create mode 100644 test/dm/reset.c diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 686c215aea..879b30e3cc 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -259,6 +259,17 @@ compatible = "sandbox,reset"; }; + resetc: reset-ctl { + compatible = "sandbox,reset-ctl"; + #reset-cells = <1>; + }; + + reset-ctl-test { + compatible = "sandbox,reset-ctl-test"; + resets = <&resetc 100>, <&resetc 2>; + reset-names = "other", "test"; + }; + rproc_1: rproc@1 { compatible = "sandbox,test-processor"; remoteproc-name = "remoteproc-test-dev1"; diff --git a/arch/sandbox/include/asm/reset.h b/arch/sandbox/include/asm/reset.h new file mode 100644 index 0000000000..7146aa5ab2 --- /dev/null +++ b/arch/sandbox/include/asm/reset.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __SANDBOX_RESET_H +#define __SANDBOX_RESET_H + +#include + +struct udevice; + +int sandbox_reset_query(struct udevice *dev, unsigned long id); + +int sandbox_reset_test_get(struct udevice *dev); +int sandbox_reset_test_assert(struct udevice *dev); +int sandbox_reset_test_deassert(struct udevice *dev); +int sandbox_reset_test_free(struct udevice *dev); + +#endif diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 4eb3c224fd..94253a65e4 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -1,4 +1,5 @@ CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_BLK=y CONFIG_MMC=y CONFIG_PCI=y CONFIG_DEFAULT_DEVICE_TREE="sandbox" @@ -70,7 +71,6 @@ CONFIG_DEVRES=y CONFIG_DEBUG_DEVRES=y CONFIG_ADC=y CONFIG_ADC_SANDBOX=y -CONFIG_BLK=y CONFIG_CLK=y CONFIG_CPU=y CONFIG_DM_DEMO=y @@ -89,6 +89,9 @@ CONFIG_I2C_ARB_GPIO_CHALLENGE=y CONFIG_CROS_EC_KEYB=y CONFIG_LED=y CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_SANDBOX_MBOX=y +CONFIG_MISC=y CONFIG_CMD_CROS_EC=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y @@ -140,6 +143,8 @@ CONFIG_DM_REGULATOR_SANDBOX=y CONFIG_REGULATOR_TPS65090=y CONFIG_RAM=y CONFIG_REMOTEPROC_SANDBOX=y +CONFIG_DM_RESET=y +CONFIG_SANDBOX_RESET=y CONFIG_DM_RTC=y CONFIG_SANDBOX_SERIAL=y CONFIG_SOUND=y @@ -170,6 +175,3 @@ CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y CONFIG_UT_ENV=y -CONFIG_MISC=y -CONFIG_DM_MAILBOX=y -CONFIG_SANDBOX_MBOX=y diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 5c449a99d3..0fe8cc3827 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -12,4 +12,12 @@ config DM_RESET although driving such reset isgnals using GPIOs may be more appropriate in this case. +config SANDBOX_RESET + bool "Enable the sandbox reset test driver" + depends on DM_MAILBOX && SANDBOX + help + Enable support for a test reset controller implementation, which + simply accepts requests to reset various HW modules without actually + doing anything beyond a little error checking. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 508608e83f..71f3b21961 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -3,3 +3,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DM_RESET) += reset-uclass.o +obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset.o +obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset-test.o diff --git a/drivers/reset/sandbox-reset-test.c b/drivers/reset/sandbox-reset-test.c new file mode 100644 index 0000000000..e37d6c91ef --- /dev/null +++ b/drivers/reset/sandbox-reset-test.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +struct sandbox_reset_test { + struct reset_ctl ctl; +}; + +int sandbox_reset_test_get(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + + return reset_get_by_name(dev, "test", &sbrt->ctl); +} + +int sandbox_reset_test_assert(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + + return reset_assert(&sbrt->ctl); +} + +int sandbox_reset_test_deassert(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + + return reset_deassert(&sbrt->ctl); +} + +int sandbox_reset_test_free(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + + return reset_free(&sbrt->ctl); +} + +static const struct udevice_id sandbox_reset_test_ids[] = { + { .compatible = "sandbox,reset-ctl-test" }, + { } +}; + +U_BOOT_DRIVER(sandbox_reset_test) = { + .name = "sandbox_reset_test", + .id = UCLASS_MISC, + .of_match = sandbox_reset_test_ids, + .priv_auto_alloc_size = sizeof(struct sandbox_reset_test), +}; diff --git a/drivers/reset/sandbox-reset.c b/drivers/reset/sandbox-reset.c new file mode 100644 index 0000000000..4258af521b --- /dev/null +++ b/drivers/reset/sandbox-reset.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +#define SANDBOX_RESET_SIGNALS 3 + +struct sandbox_reset_signal { + bool asserted; +}; + +struct sandbox_reset { + struct sandbox_reset_signal signals[SANDBOX_RESET_SIGNALS]; +}; + +static int sandbox_reset_request(struct reset_ctl *reset_ctl) +{ + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + + if (reset_ctl->id >= SANDBOX_RESET_SIGNALS) + return -EINVAL; + + return 0; +} + +static int sandbox_reset_free(struct reset_ctl *reset_ctl) +{ + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + + return 0; +} + +static int sandbox_reset_assert(struct reset_ctl *reset_ctl) +{ + struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev); + + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + + sbr->signals[reset_ctl->id].asserted = true; + + return 0; +} + +static int sandbox_reset_deassert(struct reset_ctl *reset_ctl) +{ + struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev); + + debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); + + sbr->signals[reset_ctl->id].asserted = false; + + return 0; +} + +static int sandbox_reset_bind(struct udevice *dev) +{ + debug("%s(dev=%p)\n", __func__, dev); + + return 0; +} + +static int sandbox_reset_probe(struct udevice *dev) +{ + debug("%s(dev=%p)\n", __func__, dev); + + return 0; +} + +static const struct udevice_id sandbox_reset_ids[] = { + { .compatible = "sandbox,reset-ctl" }, + { } +}; + +struct reset_ops sandbox_reset_reset_ops = { + .request = sandbox_reset_request, + .free = sandbox_reset_free, + .rst_assert = sandbox_reset_assert, + .rst_deassert = sandbox_reset_deassert, +}; + +U_BOOT_DRIVER(sandbox_reset) = { + .name = "sandbox_reset", + .id = UCLASS_RESET, + .of_match = sandbox_reset_ids, + .bind = sandbox_reset_bind, + .probe = sandbox_reset_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_reset), + .ops = &sandbox_reset_reset_ops, +}; + +int sandbox_reset_query(struct udevice *dev, unsigned long id) +{ + struct sandbox_reset *sbr = dev_get_priv(dev); + + debug("%s(dev=%p, id=%ld)\n", __func__, dev, id); + + if (id >= SANDBOX_RESET_SIGNALS) + return -EINVAL; + + return sbr->signals[id].asserted; +} diff --git a/test/dm/Makefile b/test/dm/Makefile index 9eaf04b9ba..cad3374e43 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_DM_PCI) += pci.o obj-$(CONFIG_RAM) += ram.o obj-y += regmap.o obj-$(CONFIG_REMOTEPROC) += remoteproc.o +obj-$(CONFIG_DM_RESET) += reset.o obj-$(CONFIG_SYSRESET) += sysreset.o obj-$(CONFIG_DM_RTC) += rtc.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o diff --git a/test/dm/reset.c b/test/dm/reset.c new file mode 100644 index 0000000000..0ae8031540 --- /dev/null +++ b/test/dm/reset.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include +#include + +/* This must match the specifier for mbox-names="test" in the DT node */ +#define TEST_RESET_ID 2 + +static int dm_test_reset(struct unit_test_state *uts) +{ + struct udevice *dev_reset; + struct udevice *dev_test; + + ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl", + &dev_reset)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test", + &dev_test)); + ut_assertok(sandbox_reset_test_get(dev_test)); + + ut_assertok(sandbox_reset_test_assert(dev_test)); + ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_assertok(sandbox_reset_test_deassert(dev_test)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_assertok(sandbox_reset_test_free(dev_test)); + + return 0; +} +DM_TEST(dm_test_reset, DM_TESTF_SCAN_FDT); -- cgit v1.2.1 From 135aa95002646c46e89de93fa36adad1b010548f Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 17 Jun 2016 09:44:00 -0600 Subject: clk: convert API to match reset/mailbox style The following changes are made to the clock API: * The concept of "clocks" and "peripheral clocks" are unified; each clock provider now implements a single set of clocks. This provides a simpler conceptual interface to clients, and better aligns with device tree clock bindings. * Clocks are now identified with a single "struct clk", rather than requiring clients to store the clock provider device and clock identity values separately. For simple clock consumers, this isolates clients from internal details of the clock API. * clk.h is split so it only contains the client/consumer API, whereas clk-uclass.h contains the provider API. This aligns with the recently added reset and mailbox APIs. * clk_ops .of_xlate(), .request(), and .free() are added so providers can customize these operations if needed. This also aligns with the recently added reset and mailbox APIs. * clk_disable() is added. * All users of the current clock APIs are updated. * Sandbox clock tests are updated to exercise clock lookup via DT, and clock enable/disable. * rkclk_get_clk() is removed and replaced with standard APIs. Buildman shows no clock-related errors for any board for which buildman can download a toolchain. test/py passes for sandbox (which invokes the dm clk test amongst others). Signed-off-by: Stephen Warren Acked-by: Simon Glass --- arch/arm/include/asm/arch-rockchip/clock.h | 12 -- arch/arm/mach-rockchip/board.c | 39 ++++- arch/arm/mach-rockchip/rk3288/sdram_rk3288.c | 15 +- arch/arm/mach-snapdragon/clock-apq8016.c | 10 +- arch/arm/mach-zynq/clk.c | 1 - arch/mips/mach-pic32/cpu.c | 45 +++--- arch/sandbox/dts/test.dts | 17 ++- arch/sandbox/include/asm/clk.h | 111 ++++++++++++++ arch/sandbox/include/asm/test.h | 9 -- board/microchip/pic32mzda/pic32mzda.c | 21 ++- drivers/clk/Makefile | 1 + drivers/clk/clk-uclass.c | 202 +++++++++++++++++------- drivers/clk/clk_fixed_rate.c | 13 +- drivers/clk/clk_pic32.c | 32 ++-- drivers/clk/clk_rk3036.c | 83 +++------- drivers/clk/clk_rk3288.c | 143 ++++------------- drivers/clk/clk_sandbox.c | 85 +++++++---- drivers/clk/clk_sandbox_test.c | 101 ++++++++++++ drivers/clk/exynos/clk-exynos7420.c | 42 ++--- drivers/clk/uniphier/clk-uniphier-core.c | 26 ++-- drivers/clk/uniphier/clk-uniphier-mio.c | 1 - drivers/i2c/rk_i2c.c | 6 +- drivers/mmc/msm_sdhci.c | 13 +- drivers/mmc/rockchip_dw_mmc.c | 6 +- drivers/mmc/uniphier-sd.c | 15 +- drivers/serial/serial_msm.c | 13 +- drivers/serial/serial_pic32.c | 7 +- drivers/serial/serial_s5p.c | 6 +- drivers/spi/rk_spi.c | 6 +- drivers/usb/host/ehci-generic.c | 14 +- drivers/video/rockchip/rk_edp.c | 11 +- drivers/video/rockchip/rk_hdmi.c | 12 +- drivers/video/rockchip/rk_lvds.c | 1 - drivers/video/rockchip/rk_vop.c | 11 +- include/clk-uclass.h | 95 ++++++++++++ include/clk.h | 220 ++++++++++++++++----------- test/dm/clk.c | 110 ++++++++++---- 37 files changed, 985 insertions(+), 570 deletions(-) create mode 100644 arch/sandbox/include/asm/clk.h create mode 100644 drivers/clk/clk_sandbox_test.c create mode 100644 include/clk-uclass.h diff --git a/arch/arm/include/asm/arch-rockchip/clock.h b/arch/arm/include/asm/arch-rockchip/clock.h index d66b26f18e..317e5128ed 100644 --- a/arch/arm/include/asm/arch-rockchip/clock.h +++ b/arch/arm/include/asm/arch-rockchip/clock.h @@ -62,18 +62,6 @@ static inline u32 clk_get_divisor(ulong input_rate, uint output_rate) */ void *rockchip_get_cru(void); -/** - * rkclk_get_clk() - get a pointer to a given clock - * - * This is an internal function - use outside the clock subsystem indicates - * that work is needed! - * - * @clk_id: Clock requested - * @devp: Returns a pointer to that clock - * @return 0 if OK, -ve on error - */ -int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp); - struct rk3288_cru; struct rk3288_grf; diff --git a/arch/arm/mach-rockchip/board.c b/arch/arm/mach-rockchip/board.c index 133d66341b..816540e582 100644 --- a/arch/arm/mach-rockchip/board.c +++ b/arch/arm/mach-rockchip/board.c @@ -9,6 +9,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -54,15 +55,43 @@ void lowlevel_init(void) static int do_clock(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { + static const struct { + char *name; + int id; + } clks[] = { + { "osc", CLK_OSC }, + { "apll", CLK_ARM }, + { "dpll", CLK_DDR }, + { "cpll", CLK_CODEC }, + { "gpll", CLK_GENERAL }, +#ifdef CONFIG_ROCKCHIP_RK3036 + { "mpll", CLK_NEW }, +#else + { "npll", CLK_NEW }, +#endif + }; + int ret, i; struct udevice *dev; - for (uclass_first_device(UCLASS_CLK, &dev); - dev; - uclass_next_device(&dev)) { + ret = uclass_get_device(UCLASS_CLK, 0, &dev); + if (ret) { + printf("clk-uclass not found\n"); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(clks); i++) { + struct clk clk; ulong rate; - rate = clk_get_rate(dev); - printf("%s: %lu\n", dev->name, rate); + clk.id = clks[i].id; + ret = clk_request(dev, &clk); + if (ret < 0) + continue; + + rate = clk_get_rate(&clk); + printf("%s: %lu\n", clks[i].name, rate); + + clk_free(&clk); } return 0; diff --git a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c index 2e21282335..55ac73e9d2 100644 --- a/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c +++ b/arch/arm/mach-rockchip/rk3288/sdram_rk3288.c @@ -36,7 +36,7 @@ struct chan_info { struct dram_info { struct chan_info chan[2]; struct ram_info info; - struct udevice *ddr_clk; + struct clk ddr_clk; struct rk3288_cru *cru; struct rk3288_grf *grf; struct rk3288_sgrf *sgrf; @@ -576,7 +576,7 @@ static void dram_all_config(const struct dram_info *dram, rk_clrsetreg(&dram->sgrf->soc_con2, 0x1f, sdram_params->base.stride); } -static int sdram_init(const struct dram_info *dram, +static int sdram_init(struct dram_info *dram, const struct rk3288_sdram_params *sdram_params) { int channel; @@ -592,8 +592,8 @@ static int sdram_init(const struct dram_info *dram, return -E2BIG; } - debug("ddr clk %s\n", dram->ddr_clk->name); - ret = clk_set_rate(dram->ddr_clk, sdram_params->base.ddr_freq); + debug("ddr clk dpll\n"); + ret = clk_set_rate(&dram->ddr_clk, sdram_params->base.ddr_freq); debug("ret=%d\n", ret); if (ret) { debug("Could not set DDR clock\n"); @@ -836,6 +836,7 @@ static int rk3288_dmc_probe(struct udevice *dev) struct dram_info *priv = dev_get_priv(dev); struct regmap *map; int ret; + struct udevice *dev_clk; map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC); if (IS_ERR(map)) @@ -856,7 +857,11 @@ static int rk3288_dmc_probe(struct udevice *dev) priv->chan[1].pctl = regmap_get_range(map, 2); priv->chan[1].publ = regmap_get_range(map, 3); - ret = uclass_get_device(UCLASS_CLK, CLK_DDR, &priv->ddr_clk); + ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk); + if (ret) + return ret; + priv->ddr_clk.id = CLK_DDR; + ret = clk_request(dev_clk, &priv->ddr_clk); if (ret) return ret; diff --git a/arch/arm/mach-snapdragon/clock-apq8016.c b/arch/arm/mach-snapdragon/clock-apq8016.c index d548d757d3..c2cf92494a 100644 --- a/arch/arm/mach-snapdragon/clock-apq8016.c +++ b/arch/arm/mach-snapdragon/clock-apq8016.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include #include #include @@ -212,11 +212,11 @@ static int clk_init_uart(struct msm_clk_priv *priv) return 0; } -ulong msm_set_periph_rate(struct udevice *dev, int periph, ulong rate) +ulong msm_set_rate(struct clk *clk, ulong rate) { - struct msm_clk_priv *priv = dev_get_priv(dev); + struct msm_clk_priv *priv = dev_get_priv(clk->dev); - switch (periph) { + switch (clk->id) { case 0: /* SDC1 */ return clk_init_sdc(priv, 0, rate); break; @@ -243,7 +243,7 @@ static int msm_clk_probe(struct udevice *dev) } static struct clk_ops msm_clk_ops = { - .set_periph_rate = msm_set_periph_rate, + .set_rate = msm_set_rate, }; static const struct udevice_id msm_clk_ids[] = { diff --git a/arch/arm/mach-zynq/clk.c b/arch/arm/mach-zynq/clk.c index 6444be8f03..40383c11c9 100644 --- a/arch/arm/mach-zynq/clk.c +++ b/arch/arm/mach-zynq/clk.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include #include diff --git a/arch/mips/mach-pic32/cpu.c b/arch/mips/mach-pic32/cpu.c index f2ee911df4..ac33391921 100644 --- a/arch/mips/mach-pic32/cpu.c +++ b/arch/mips/mach-pic32/cpu.c @@ -23,18 +23,34 @@ DECLARE_GLOBAL_DATA_PTR; -static ulong clk_get_cpu_rate(void) +static ulong rate(int id) { int ret; struct udevice *dev; + struct clk clk; + ulong rate; ret = uclass_get_device(UCLASS_CLK, 0, &dev); if (ret) { - panic("uclass-clk: device not found\n"); + printf("clk-uclass not found\n"); return 0; } - return clk_get_rate(dev); + clk.id = id; + ret = clk_request(dev, &clk); + if (ret < 0) + return ret; + + rate = clk_get_rate(&clk); + + clk_free(&clk); + + return rate; +} + +static ulong clk_get_cpu_rate(void) +{ + return rate(PB7CLK); } /* initialize prefetch module related to cpu_clk */ @@ -127,30 +143,25 @@ const char *get_core_name(void) } #endif #ifdef CONFIG_CMD_CLK + int soc_clk_dump(void) { - int i, ret; - struct udevice *dev; - - ret = uclass_get_device(UCLASS_CLK, 0, &dev); - if (ret) { - printf("clk-uclass not found\n"); - return ret; - } + int i; printf("PLL Speed: %lu MHz\n", - CLK_MHZ(clk_get_periph_rate(dev, PLLCLK))); - printf("CPU Speed: %lu MHz\n", CLK_MHZ(clk_get_rate(dev))); - printf("MPLL Speed: %lu MHz\n", - CLK_MHZ(clk_get_periph_rate(dev, MPLL))); + CLK_MHZ(rate(PLLCLK))); + + printf("CPU Speed: %lu MHz\n", CLK_MHZ(rate(PB7CLK))); + + printf("MPLL Speed: %lu MHz\n", CLK_MHZ(rate(MPLL))); for (i = PB1CLK; i <= PB7CLK; i++) printf("PB%d Clock Speed: %lu MHz\n", i - PB1CLK + 1, - CLK_MHZ(clk_get_periph_rate(dev, i))); + CLK_MHZ(rate(i))); for (i = REF1CLK; i <= REF5CLK; i++) printf("REFO%d Clock Speed: %lu MHz\n", i - REF1CLK + 1, - CLK_MHZ(clk_get_periph_rate(dev, i))); + CLK_MHZ(rate(i))); return 0; } #endif diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 879b30e3cc..9e46f9e815 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -108,8 +108,23 @@ compatible = "denx,u-boot-fdt-test"; }; - clk@0 { + clk_fixed: clk-fixed { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1234>; + }; + + clk_sandbox: clk-sbox { compatible = "sandbox,clk"; + #clock-cells = <1>; + }; + + clk-test { + compatible = "sandbox,clk-test"; + clocks = <&clk_fixed>, + <&clk_sandbox 1>, + <&clk_sandbox 0>; + clock-names = "fixed", "i2c", "spi"; }; eth@10002000 { diff --git a/arch/sandbox/include/asm/clk.h b/arch/sandbox/include/asm/clk.h new file mode 100644 index 0000000000..9dc6c8184b --- /dev/null +++ b/arch/sandbox/include/asm/clk.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __SANDBOX_CLK_H +#define __SANDBOX_CLK_H + +#include + +struct udevice; + +/** + * enum sandbox_clk_id - Identity of clocks implemented by the sandbox clock + * provider. + * + * These IDs are within/relative-to the clock provider. + */ +enum sandbox_clk_id { + SANDBOX_CLK_ID_SPI, + SANDBOX_CLK_ID_I2C, + + SANDBOX_CLK_ID_COUNT, +}; + +/** + * enum sandbox_clk_test_id - Identity of the clocks consumed by the sandbox + * clock test device. + * + * These are the IDs the clock consumer knows the clocks as. + */ +enum sandbox_clk_test_id { + SANDBOX_CLK_TEST_ID_FIXED, + SANDBOX_CLK_TEST_ID_SPI, + SANDBOX_CLK_TEST_ID_I2C, + + SANDBOX_CLK_TEST_ID_COUNT, +}; + +/** + * sandbox_clk_query_rate - Query the current rate of a sandbox clock. + * + * @dev: The sandbox clock provider device. + * @id: The clock to query. + * @return: The rate of the clock. + */ +ulong sandbox_clk_query_rate(struct udevice *dev, int id); +/** + * sandbox_clk_query_enable - Query the enable state of a sandbox clock. + * + * @dev: The sandbox clock provider device. + * @id: The clock to query. + * @return: The rate of the clock. + */ +int sandbox_clk_query_enable(struct udevice *dev, int id); + +/** + * sandbox_clk_test_get - Ask the sandbox clock test device to request its + * clocks. + * + * @dev: The sandbox clock test (client) devivce. + * @return: 0 if OK, or a negative error code. + */ +int sandbox_clk_test_get(struct udevice *dev); +/** + * sandbox_clk_test_get_rate - Ask the sandbox clock test device to query a + * clock's rate. + * + * @dev: The sandbox clock test (client) devivce. + * @id: The test device's clock ID to query. + * @return: The rate of the clock. + */ +ulong sandbox_clk_test_get_rate(struct udevice *dev, int id); +/** + * sandbox_clk_test_set_rate - Ask the sandbox clock test device to set a + * clock's rate. + * + * @dev: The sandbox clock test (client) devivce. + * @id: The test device's clock ID to configure. + * @return: The new rate of the clock. + */ +ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate); +/** + * sandbox_clk_test_enable - Ask the sandbox clock test device to enable a + * clock. + * + * @dev: The sandbox clock test (client) devivce. + * @id: The test device's clock ID to configure. + * @return: 0 if OK, or a negative error code. + */ +int sandbox_clk_test_enable(struct udevice *dev, int id); +/** + * sandbox_clk_test_disable - Ask the sandbox clock test device to disable a + * clock. + * + * @dev: The sandbox clock test (client) devivce. + * @id: The test device's clock ID to configure. + * @return: 0 if OK, or a negative error code. + */ +int sandbox_clk_test_disable(struct udevice *dev, int id); +/** + * sandbox_clk_test_free - Ask the sandbox clock test device to free its + * clocks. + * + * @dev: The sandbox clock test (client) devivce. + * @return: 0 if OK, or a negative error code. + */ +int sandbox_clk_test_free(struct udevice *dev); + +#endif diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 224b0ebaf9..451a78e590 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -19,15 +19,6 @@ #define SANDBOX_CLK_RATE 32768 -enum { - PERIPH_ID_FIRST = 0, - PERIPH_ID_SPI = PERIPH_ID_FIRST, - PERIPH_ID_I2C, - PERIPH_ID_PCI, - - PERIPH_ID_COUNT, -}; - /* System controller driver data */ enum { SYSCON0 = 32, diff --git a/board/microchip/pic32mzda/pic32mzda.c b/board/microchip/pic32mzda/pic32mzda.c index afe2ab8b71..3d31d3d062 100644 --- a/board/microchip/pic32mzda/pic32mzda.c +++ b/board/microchip/pic32mzda/pic32mzda.c @@ -11,20 +11,31 @@ #include #include #include +#include #include #ifdef CONFIG_DISPLAY_BOARDINFO int checkboard(void) { - ulong rate = 0; + ulong rate; struct udevice *dev; + struct clk clk; + int ret; printf("Core: %s\n", get_core_name()); - if (!uclass_get_device(UCLASS_CLK, 0, &dev)) { - rate = clk_get_rate(dev); - printf("CPU Speed: %lu MHz\n", rate / 1000000); - } + if (uclass_get_device(UCLASS_CLK, 0, &dev)) + return 0; + + clk.id = PB7CLK; + ret = clk_request(dev, &clk); + if (ret < 0) + return 0; + + rate = clk_get_rate(&clk); + printf("CPU Speed: %lu MHz\n", rate / 1000000); + + clk_free(&clk); return 0; } diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 81fe600188..f7a88912e0 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CLK) += clk-uclass.o clk_fixed_rate.o obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o obj-$(CONFIG_SANDBOX) += clk_sandbox.o +obj-$(CONFIG_SANDBOX) += clk_sandbox_test.o obj-$(CONFIG_MACH_PIC32) += clk_pic32.o obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index b483c1ef33..6e4d67220a 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -1,91 +1,78 @@ /* * Copyright (C) 2015 Google, Inc * Written by Simon Glass + * Copyright (c) 2016, NVIDIA CORPORATION. * * SPDX-License-Identifier: GPL-2.0+ */ #include #include +#include #include #include -#include -#include DECLARE_GLOBAL_DATA_PTR; -ulong clk_get_rate(struct udevice *dev) +static inline struct clk_ops *clk_dev_ops(struct udevice *dev) { - struct clk_ops *ops = clk_get_ops(dev); - - if (!ops->get_rate) - return -ENOSYS; - - return ops->get_rate(dev); + return (struct clk_ops *)dev->driver->ops; } -ulong clk_set_rate(struct udevice *dev, ulong rate) +#if CONFIG_IS_ENABLED(OF_CONTROL) +#ifdef CONFIG_SPL_BUILD +int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) { - struct clk_ops *ops = clk_get_ops(dev); + int ret; + u32 cell[2]; - if (!ops->set_rate) + if (index != 0) return -ENOSYS; - - return ops->set_rate(dev, rate); + assert(clk); + ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev); + if (ret) + return ret; + ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clocks", + cell, 2); + if (ret) + return ret; + clk->id = cell[1]; + return 0; } -int clk_enable(struct udevice *dev, int periph) +int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) { - struct clk_ops *ops = clk_get_ops(dev); - - if (!ops->enable) - return -ENOSYS; - - return ops->enable(dev, periph); + return -ENOSYS; } - -ulong clk_get_periph_rate(struct udevice *dev, int periph) +#else +static int clk_of_xlate_default(struct clk *clk, + struct fdtdec_phandle_args *args) { - struct clk_ops *ops = clk_get_ops(dev); + debug("%s(clk=%p)\n", __func__, clk); - if (!ops->get_periph_rate) - return -ENOSYS; - - return ops->get_periph_rate(dev, periph); -} - -ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate) -{ - struct clk_ops *ops = clk_get_ops(dev); + if (args->args_count > 1) { + debug("Invaild args_count: %d\n", args->args_count); + return -EINVAL; + } - if (!ops->set_periph_rate) - return -ENOSYS; + if (args->args_count) + clk->id = args->args[0]; + else + clk->id = 0; - return ops->set_periph_rate(dev, periph, rate); + return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) -int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp) +int clk_get_by_index(struct udevice *dev, int index, struct clk *clk) { int ret; -#ifdef CONFIG_SPL_BUILD - u32 cell[2]; - - if (index != 0) - return -ENOSYS; - assert(*clk_devp); - ret = uclass_get_device(UCLASS_CLK, 0, clk_devp); - if (ret) - return ret; - ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clocks", - cell, 2); - if (ret) - return ret; - return cell[1]; -#else struct fdtdec_phandle_args args; + struct udevice *dev_clk; + struct clk_ops *ops; + + debug("%s(dev=%p, index=%d, clk=%p)\n", __func__, dev, index, clk); - assert(*clk_devp); + assert(clk); ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, "clocks", "#clock-cells", 0, index, &args); @@ -95,16 +82,117 @@ int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp) return ret; } - ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, clk_devp); + ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev_clk); if (ret) { debug("%s: uclass_get_device_by_of_offset failed: err=%d\n", __func__, ret); return ret; } - return args.args_count > 0 ? args.args[0] : 0; -#endif + ops = clk_dev_ops(dev_clk); + + if (ops->of_xlate) + ret = ops->of_xlate(clk, &args); + else + ret = clk_of_xlate_default(clk, &args); + if (ret) { + debug("of_xlate() failed: %d\n", ret); + return ret; + } + + return clk_request(dev_clk, clk); +} + +int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk) +{ + int index; + + debug("%s(dev=%p, name=%s, clk=%p)\n", __func__, dev, name, clk); + + index = fdt_find_string(gd->fdt_blob, dev->of_offset, "clock-names", + name); + if (index < 0) { + debug("fdt_find_string() failed: %d\n", index); + return index; + } + + return clk_get_by_index(dev, index, clk); } #endif +#endif + +int clk_request(struct udevice *dev, struct clk *clk) +{ + struct clk_ops *ops = clk_dev_ops(dev); + + debug("%s(dev=%p, clk=%p)\n", __func__, dev, clk); + + clk->dev = dev; + + if (!ops->request) + return 0; + + return ops->request(clk); +} + +int clk_free(struct clk *clk) +{ + struct clk_ops *ops = clk_dev_ops(clk->dev); + + debug("%s(clk=%p)\n", __func__, clk); + + if (!ops->free) + return 0; + + return ops->free(clk); +} + +ulong clk_get_rate(struct clk *clk) +{ + struct clk_ops *ops = clk_dev_ops(clk->dev); + + debug("%s(clk=%p)\n", __func__, clk); + + if (!ops->get_rate) + return -ENOSYS; + + return ops->get_rate(clk); +} + +ulong clk_set_rate(struct clk *clk, ulong rate) +{ + struct clk_ops *ops = clk_dev_ops(clk->dev); + + debug("%s(clk=%p, rate=%lu)\n", __func__, clk, rate); + + if (!ops->set_rate) + return -ENOSYS; + + return ops->set_rate(clk, rate); +} + +int clk_enable(struct clk *clk) +{ + struct clk_ops *ops = clk_dev_ops(clk->dev); + + debug("%s(clk=%p)\n", __func__, clk); + + if (!ops->enable) + return -ENOSYS; + + return ops->enable(clk); +} + +int clk_disable(struct clk *clk) +{ + struct clk_ops *ops = clk_dev_ops(clk->dev); + + debug("%s(clk=%p)\n", __func__, clk); + + if (!ops->disable) + return -ENOSYS; + + return ops->disable(clk); +} UCLASS_DRIVER(clk) = { .id = UCLASS_CLK, diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index 8beda9cb55..797e537907 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -16,19 +16,16 @@ struct clk_fixed_rate { #define to_clk_fixed_rate(dev) ((struct clk_fixed_rate *)dev_get_platdata(dev)) -static ulong clk_fixed_rate_get_rate(struct udevice *dev) +static ulong clk_fixed_rate_get_rate(struct clk *clk) { - return to_clk_fixed_rate(dev)->fixed_rate; -} + if (clk->id != 0) + return -EINVAL; -static ulong clk_fixed_rate_get_periph_rate(struct udevice *dev, int periph) -{ - return clk_fixed_rate_get_rate(dev); + return to_clk_fixed_rate(clk->dev)->fixed_rate; } const struct clk_ops clk_fixed_rate_ops = { .get_rate = clk_fixed_rate_get_rate, - .get_periph_rate = clk_fixed_rate_get_periph_rate, }; static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev) diff --git a/drivers/clk/clk_pic32.c b/drivers/clk/clk_pic32.c index 5d883544d5..70ec3543cf 100644 --- a/drivers/clk/clk_pic32.c +++ b/drivers/clk/clk_pic32.c @@ -6,7 +6,7 @@ */ #include -#include +#include #include #include #include @@ -339,24 +339,17 @@ static void pic32_clk_init(struct udevice *dev) pic32_mpll_init(priv); } -static ulong pic32_clk_get_rate(struct udevice *dev) +static ulong pic32_get_rate(struct clk *clk) { - struct pic32_clk_priv *priv = dev_get_priv(dev); - - return pic32_get_cpuclk(priv); -} - -static ulong pic32_get_periph_rate(struct udevice *dev, int periph) -{ - struct pic32_clk_priv *priv = dev_get_priv(dev); + struct pic32_clk_priv *priv = dev_get_priv(clk->dev); ulong rate; - switch (periph) { + switch (clk->id) { case PB1CLK ... PB7CLK: - rate = pic32_get_pbclk(priv, periph); + rate = pic32_get_pbclk(priv, clk->id); break; case REF1CLK ... REF5CLK: - rate = pic32_get_refclk(priv, periph); + rate = pic32_get_refclk(priv, clk->id); break; case PLLCLK: rate = pic32_get_pll_rate(priv); @@ -372,15 +365,15 @@ static ulong pic32_get_periph_rate(struct udevice *dev, int periph) return rate; } -static ulong pic32_set_periph_rate(struct udevice *dev, int periph, ulong rate) +static ulong pic32_set_rate(struct clk *clk, ulong rate) { - struct pic32_clk_priv *priv = dev_get_priv(dev); + struct pic32_clk_priv *priv = dev_get_priv(clk->dev); ulong pll_hz; - switch (periph) { + switch (clk->id) { case REF1CLK ... REF5CLK: pll_hz = pic32_get_pll_rate(priv); - pic32_set_refclk(priv, periph, pll_hz, rate, ROCLK_SRC_SPLL); + pic32_set_refclk(priv, clk->id, pll_hz, rate, ROCLK_SRC_SPLL); break; default: break; @@ -390,9 +383,8 @@ static ulong pic32_set_periph_rate(struct udevice *dev, int periph, ulong rate) } static struct clk_ops pic32_pic32_clk_ops = { - .get_rate = pic32_clk_get_rate, - .set_periph_rate = pic32_set_periph_rate, - .get_periph_rate = pic32_get_periph_rate, + .set_rate = pic32_set_rate, + .get_rate = pic32_get_rate, }; static int pic32_clk_probe(struct udevice *dev) diff --git a/drivers/clk/clk_rk3036.c b/drivers/clk/clk_rk3036.c index 7ec65bdff0..6202c9da5d 100644 --- a/drivers/clk/clk_rk3036.c +++ b/drivers/clk/clk_rk3036.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include @@ -18,10 +18,6 @@ DECLARE_GLOBAL_DATA_PTR; -struct rk3036_clk_plat { - enum rk_clk_id clk_id; -}; - struct rk3036_clk_priv { struct rk3036_cru *cru; ulong rate; @@ -315,31 +311,30 @@ static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate, return rockchip_mmc_get_clk(cru, clk_general_rate, periph); } -static ulong rk3036_clk_get_rate(struct udevice *dev) -{ - struct rk3036_clk_plat *plat = dev_get_platdata(dev); - struct rk3036_clk_priv *priv = dev_get_priv(dev); - - debug("%s\n", dev->name); - return rkclk_pll_get_rate(priv->cru, plat->clk_id); -} - -static ulong rk3036_clk_set_rate(struct udevice *dev, ulong rate) +static ulong rk3036_clk_get_rate(struct clk *clk) { - debug("%s\n", dev->name); + struct rk3036_clk_priv *priv = dev_get_priv(clk->dev); - return 0; + switch (clk->id) { + case 0 ... 63: + return rkclk_pll_get_rate(priv->cru, clk->id); + default: + return -ENOENT; + } } -static ulong rk3036_set_periph_rate(struct udevice *dev, int periph, ulong rate) +static ulong rk3036_clk_set_rate(struct clk *clk, ulong rate) { - struct rk3036_clk_priv *priv = dev_get_priv(dev); - ulong new_rate; + struct rk3036_clk_priv *priv = dev_get_priv(clk->dev); + ulong new_rate, gclk_rate; - switch (periph) { + gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case 0 ... 63: + return 0; case HCLK_EMMC: - new_rate = rockchip_mmc_set_clk(priv->cru, clk_get_rate(dev), - periph, rate); + new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate, + clk->id, rate); break; default: return -ENOENT; @@ -351,60 +346,21 @@ static ulong rk3036_set_periph_rate(struct udevice *dev, int periph, ulong rate) static struct clk_ops rk3036_clk_ops = { .get_rate = rk3036_clk_get_rate, .set_rate = rk3036_clk_set_rate, - .set_periph_rate = rk3036_set_periph_rate, }; static int rk3036_clk_probe(struct udevice *dev) { - struct rk3036_clk_plat *plat = dev_get_platdata(dev); struct rk3036_clk_priv *priv = dev_get_priv(dev); - if (plat->clk_id != CLK_OSC) { - struct rk3036_clk_priv *parent_priv = dev_get_priv(dev->parent); - - priv->cru = parent_priv->cru; - return 0; - } priv->cru = (struct rk3036_cru *)dev_get_addr(dev); rkclk_init(priv->cru); return 0; } -static const char *const clk_name[] = { - "osc", - "apll", - "dpll", - "cpll", - "gpll", - "mpll", -}; - static int rk3036_clk_bind(struct udevice *dev) { - struct rk3036_clk_plat *plat = dev_get_platdata(dev); - int pll, ret; - - /* We only need to set up the root clock */ - if (dev->of_offset == -1) { - plat->clk_id = CLK_OSC; - return 0; - } - - /* Create devices for P main clocks */ - for (pll = 1; pll < CLK_COUNT; pll++) { - struct udevice *child; - struct rk3036_clk_plat *cplat; - - debug("%s %s\n", __func__, clk_name[pll]); - ret = device_bind_driver(dev, "clk_rk3036", clk_name[pll], - &child); - if (ret) - return ret; - - cplat = dev_get_platdata(child); - cplat->clk_id = pll; - } + int ret; /* The reset driver does not have a device node, so bind it here */ ret = device_bind_driver(gd->dm_root, "rk3036_sysreset", "reset", &dev); @@ -424,7 +380,6 @@ U_BOOT_DRIVER(clk_rk3036) = { .id = UCLASS_CLK, .of_match = rk3036_clk_ids, .priv_auto_alloc_size = sizeof(struct rk3036_clk_priv), - .platdata_auto_alloc_size = sizeof(struct rk3036_clk_plat), .ops = &rk3036_clk_ops, .bind = rk3036_clk_bind, .probe = rk3036_clk_probe, diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c index d88893c8ea..2285453e8d 100644 --- a/drivers/clk/clk_rk3288.c +++ b/drivers/clk/clk_rk3288.c @@ -5,7 +5,7 @@ */ #include -#include +#include #include #include #include @@ -21,10 +21,6 @@ DECLARE_GLOBAL_DATA_PTR; -struct rk3288_clk_plat { - enum rk_clk_id clk_id; -}; - struct rk3288_clk_priv { struct rk3288_grf *grf; struct rk3288_cru *cru; @@ -135,34 +131,18 @@ static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 1); static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2); static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2); -int rkclk_get_clk(enum rk_clk_id clk_id, struct udevice **devp) -{ - struct udevice *dev; - - for (uclass_find_first_device(UCLASS_CLK, &dev); - dev; - uclass_find_next_device(&dev)) { - struct rk3288_clk_plat *plat = dev_get_platdata(dev); - - if (plat->clk_id == clk_id) { - *devp = dev; - return device_probe(dev); - } - } - - return -ENODEV; -} - void *rockchip_get_cru(void) { struct rk3288_clk_priv *priv; struct udevice *dev; int ret; - ret = rkclk_get_clk(CLK_GENERAL, &dev); + ret = uclass_get_device(UCLASS_CLK, 0, &dev); if (ret) return ERR_PTR(ret); + priv = dev_get_priv(dev); + return priv->cru; } @@ -539,32 +519,6 @@ static uint32_t rkclk_pll_get_rate(struct rk3288_cru *cru, } } -static ulong rk3288_clk_get_rate(struct udevice *dev) -{ - struct rk3288_clk_plat *plat = dev_get_platdata(dev); - struct rk3288_clk_priv *priv = dev_get_priv(dev); - - debug("%s\n", dev->name); - return rkclk_pll_get_rate(priv->cru, plat->clk_id); -} - -static ulong rk3288_clk_set_rate(struct udevice *dev, ulong rate) -{ - struct rk3288_clk_plat *plat = dev_get_platdata(dev); - struct rk3288_clk_priv *priv = dev_get_priv(dev); - - debug("%s\n", dev->name); - switch (plat->clk_id) { - case CLK_DDR: - rkclk_configure_ddr(priv->cru, priv->grf, rate); - break; - default: - return -ENOENT; - } - - return 0; -} - static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate, int periph) { @@ -710,27 +664,25 @@ static ulong rockchip_spi_set_clk(struct rk3288_cru *cru, uint gclk_rate, return rockchip_spi_get_clk(cru, gclk_rate, periph); } -static ulong rk3288_get_periph_rate(struct udevice *dev, int periph) +static ulong rk3288_clk_get_rate(struct clk *clk) { - struct rk3288_clk_priv *priv = dev_get_priv(dev); - struct udevice *gclk; + struct rk3288_clk_priv *priv = dev_get_priv(clk->dev); ulong new_rate, gclk_rate; - int ret; - ret = rkclk_get_clk(CLK_GENERAL, &gclk); - if (ret) - return ret; - gclk_rate = clk_get_rate(gclk); - switch (periph) { + gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case 0 ... 63: + new_rate = rkclk_pll_get_rate(priv->cru, clk->id); + break; case HCLK_EMMC: case HCLK_SDMMC: case HCLK_SDIO0: - new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, periph); + new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, clk->id); break; case SCLK_SPI0: case SCLK_SPI1: case SCLK_SPI2: - new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, periph); + new_rate = rockchip_spi_get_clk(priv->cru, gclk_rate, clk->id); break; case PCLK_I2C0: case PCLK_I2C1: @@ -746,36 +698,34 @@ static ulong rk3288_get_periph_rate(struct udevice *dev, int periph) return new_rate; } -static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate) +static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate) { - struct rk3288_clk_priv *priv = dev_get_priv(dev); + struct rk3288_clk_priv *priv = dev_get_priv(clk->dev); struct rk3288_cru *cru = priv->cru; - struct udevice *gclk; ulong new_rate, gclk_rate; - int ret; - ret = rkclk_get_clk(CLK_GENERAL, &gclk); - if (ret) - return ret; - gclk_rate = clk_get_rate(gclk); - switch (periph) { + gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case CLK_DDR: + new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate); + break; case HCLK_EMMC: case HCLK_SDMMC: case HCLK_SDIO0: - new_rate = rockchip_mmc_set_clk(cru, gclk_rate, periph, rate); + new_rate = rockchip_mmc_set_clk(cru, gclk_rate, clk->id, rate); break; case SCLK_SPI0: case SCLK_SPI1: case SCLK_SPI2: - new_rate = rockchip_spi_set_clk(cru, gclk_rate, periph, rate); + new_rate = rockchip_spi_set_clk(cru, gclk_rate, clk->id, rate); break; #ifndef CONFIG_SPL_BUILD case SCLK_MAC: - new_rate = rockchip_mac_set_clk(priv->cru, periph, rate); + new_rate = rockchip_mac_set_clk(priv->cru, clk->id, rate); break; case DCLK_VOP0: case DCLK_VOP1: - new_rate = rockchip_vop_set_clk(cru, priv->grf, periph, rate); + new_rate = rockchip_vop_set_clk(cru, priv->grf, clk->id, rate); break; case SCLK_EDP_24M: /* clk_edp_24M source: 24M */ @@ -795,7 +745,7 @@ static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate) div = CPLL_HZ / rate; assert((div - 1 < 64) && (div * rate == CPLL_HZ)); - switch (periph) { + switch (clk->id) { case ACLK_VOP0: rk_clrsetreg(&cru->cru_clksel_con[31], 3 << 6 | 0x1f << 0, @@ -831,22 +781,12 @@ static ulong rk3288_set_periph_rate(struct udevice *dev, int periph, ulong rate) static struct clk_ops rk3288_clk_ops = { .get_rate = rk3288_clk_get_rate, .set_rate = rk3288_clk_set_rate, - .set_periph_rate = rk3288_set_periph_rate, - .get_periph_rate = rk3288_get_periph_rate, }; static int rk3288_clk_probe(struct udevice *dev) { - struct rk3288_clk_plat *plat = dev_get_platdata(dev); struct rk3288_clk_priv *priv = dev_get_priv(dev); - if (plat->clk_id != CLK_OSC) { - struct rk3288_clk_priv *parent_priv = dev_get_priv(dev->parent); - - priv->cru = parent_priv->cru; - priv->grf = parent_priv->grf; - return 0; - } priv->cru = (struct rk3288_cru *)dev_get_addr(dev); priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); #ifdef CONFIG_SPL_BUILD @@ -856,39 +796,9 @@ static int rk3288_clk_probe(struct udevice *dev) return 0; } -static const char *const clk_name[CLK_COUNT] = { - "osc", - "apll", - "dpll", - "cpll", - "gpll", - "npll", -}; - static int rk3288_clk_bind(struct udevice *dev) { - struct rk3288_clk_plat *plat = dev_get_platdata(dev); - int pll, ret; - - /* We only need to set up the root clock */ - if (dev->of_offset == -1) { - plat->clk_id = CLK_OSC; - return 0; - } - - /* Create devices for P main clocks */ - for (pll = 1; pll < CLK_COUNT; pll++) { - struct udevice *child; - struct rk3288_clk_plat *cplat; - - debug("%s %s\n", __func__, clk_name[pll]); - ret = device_bind_driver(dev, "clk_rk3288", clk_name[pll], - &child); - if (ret) - return ret; - cplat = dev_get_platdata(child); - cplat->clk_id = pll; - } + int ret; /* The reset driver does not have a device node, so bind it here */ ret = device_bind_driver(gd->dm_root, "rk3288_sysreset", "reset", &dev); @@ -908,7 +818,6 @@ U_BOOT_DRIVER(clk_rk3288) = { .id = UCLASS_CLK, .of_match = rk3288_clk_ids, .priv_auto_alloc_size = sizeof(struct rk3288_clk_priv), - .platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat), .ops = &rk3288_clk_ops, .bind = rk3288_clk_bind, .probe = rk3288_clk_probe, diff --git a/drivers/clk/clk_sandbox.c b/drivers/clk/clk_sandbox.c index 367130f8b7..c6bd7c64e2 100644 --- a/drivers/clk/clk_sandbox.c +++ b/drivers/clk/clk_sandbox.c @@ -5,61 +5,63 @@ */ #include -#include +#include #include #include -#include +#include struct sandbox_clk_priv { - ulong rate; - ulong periph_rate[PERIPH_ID_COUNT]; + ulong rate[SANDBOX_CLK_ID_COUNT]; + bool enabled[SANDBOX_CLK_ID_COUNT]; }; -static ulong sandbox_clk_get_rate(struct udevice *dev) +static ulong sandbox_clk_get_rate(struct clk *clk) { - struct sandbox_clk_priv *priv = dev_get_priv(dev); + struct sandbox_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id < 0 || clk->id >= SANDBOX_CLK_ID_COUNT) + return -EINVAL; - return priv->rate; + return priv->rate[clk->id]; } -static ulong sandbox_clk_set_rate(struct udevice *dev, ulong rate) +static ulong sandbox_clk_set_rate(struct clk *clk, ulong rate) { - struct sandbox_clk_priv *priv = dev_get_priv(dev); + struct sandbox_clk_priv *priv = dev_get_priv(clk->dev); + ulong old_rate; + + if (clk->id < 0 || clk->id >= SANDBOX_CLK_ID_COUNT) + return -EINVAL; if (!rate) return -EINVAL; - priv->rate = rate; - return 0; -} -static ulong sandbox_get_periph_rate(struct udevice *dev, int periph) -{ - struct sandbox_clk_priv *priv = dev_get_priv(dev); + old_rate = priv->rate[clk->id]; + priv->rate[clk->id] = rate; - if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT) - return -EINVAL; - return priv->periph_rate[periph]; + return old_rate; } -static ulong sandbox_set_periph_rate(struct udevice *dev, int periph, - ulong rate) +static int sandbox_clk_enable(struct clk *clk) { - struct sandbox_clk_priv *priv = dev_get_priv(dev); - ulong old_rate; + struct sandbox_clk_priv *priv = dev_get_priv(clk->dev); - if (periph < PERIPH_ID_FIRST || periph >= PERIPH_ID_COUNT) + if (clk->id < 0 || clk->id >= SANDBOX_CLK_ID_COUNT) return -EINVAL; - old_rate = priv->periph_rate[periph]; - priv->periph_rate[periph] = rate; - return old_rate; + priv->enabled[clk->id] = true; + + return 0; } -static int sandbox_clk_probe(struct udevice *dev) +static int sandbox_clk_disable(struct clk *clk) { - struct sandbox_clk_priv *priv = dev_get_priv(dev); + struct sandbox_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id < 0 || clk->id >= SANDBOX_CLK_ID_COUNT) + return -EINVAL; - priv->rate = SANDBOX_CLK_RATE; + priv->enabled[clk->id] = false; return 0; } @@ -67,8 +69,8 @@ static int sandbox_clk_probe(struct udevice *dev) static struct clk_ops sandbox_clk_ops = { .get_rate = sandbox_clk_get_rate, .set_rate = sandbox_clk_set_rate, - .get_periph_rate = sandbox_get_periph_rate, - .set_periph_rate = sandbox_set_periph_rate, + .enable = sandbox_clk_enable, + .disable = sandbox_clk_disable, }; static const struct udevice_id sandbox_clk_ids[] = { @@ -82,5 +84,24 @@ U_BOOT_DRIVER(clk_sandbox) = { .of_match = sandbox_clk_ids, .ops = &sandbox_clk_ops, .priv_auto_alloc_size = sizeof(struct sandbox_clk_priv), - .probe = sandbox_clk_probe, }; + +ulong sandbox_clk_query_rate(struct udevice *dev, int id) +{ + struct sandbox_clk_priv *priv = dev_get_priv(dev); + + if (id < 0 || id >= SANDBOX_CLK_ID_COUNT) + return -EINVAL; + + return priv->rate[id]; +} + +int sandbox_clk_query_enable(struct udevice *dev, int id) +{ + struct sandbox_clk_priv *priv = dev_get_priv(dev); + + if (id < 0 || id >= SANDBOX_CLK_ID_COUNT) + return -EINVAL; + + return priv->enabled[id]; +} diff --git a/drivers/clk/clk_sandbox_test.c b/drivers/clk/clk_sandbox_test.c new file mode 100644 index 0000000000..999100de9d --- /dev/null +++ b/drivers/clk/clk_sandbox_test.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include +#include +#include +#include + +struct sandbox_clk_test { + struct clk clks[SANDBOX_CLK_TEST_ID_COUNT]; +}; + +static const char * const sandbox_clk_test_names[] = { + [SANDBOX_CLK_TEST_ID_FIXED] = "fixed", + [SANDBOX_CLK_TEST_ID_SPI] = "spi", + [SANDBOX_CLK_TEST_ID_I2C] = "i2c", +}; + +int sandbox_clk_test_get(struct udevice *dev) +{ + struct sandbox_clk_test *sbct = dev_get_priv(dev); + int i, ret; + + for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) { + ret = clk_get_by_name(dev, sandbox_clk_test_names[i], + &sbct->clks[i]); + if (ret) + return ret; + } + + return 0; +} + +ulong sandbox_clk_test_get_rate(struct udevice *dev, int id) +{ + struct sandbox_clk_test *sbct = dev_get_priv(dev); + + if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT) + return -EINVAL; + + return clk_get_rate(&sbct->clks[id]); +} + +ulong sandbox_clk_test_set_rate(struct udevice *dev, int id, ulong rate) +{ + struct sandbox_clk_test *sbct = dev_get_priv(dev); + + if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT) + return -EINVAL; + + return clk_set_rate(&sbct->clks[id], rate); +} + +int sandbox_clk_test_enable(struct udevice *dev, int id) +{ + struct sandbox_clk_test *sbct = dev_get_priv(dev); + + if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT) + return -EINVAL; + + return clk_enable(&sbct->clks[id]); +} + +int sandbox_clk_test_disable(struct udevice *dev, int id) +{ + struct sandbox_clk_test *sbct = dev_get_priv(dev); + + if (id < 0 || id >= SANDBOX_CLK_TEST_ID_COUNT) + return -EINVAL; + + return clk_disable(&sbct->clks[id]); +} + +int sandbox_clk_test_free(struct udevice *dev) +{ + struct sandbox_clk_test *sbct = dev_get_priv(dev); + int i, ret; + + for (i = 0; i < SANDBOX_CLK_TEST_ID_COUNT; i++) { + ret = clk_free(&sbct->clks[i]); + if (ret) + return ret; + } + + return 0; +} + +static const struct udevice_id sandbox_clk_test_ids[] = { + { .compatible = "sandbox,clk-test" }, + { } +}; + +U_BOOT_DRIVER(sandbox_clk_test) = { + .name = "sandbox_clk_test", + .id = UCLASS_MISC, + .of_match = sandbox_clk_test_ids, + .priv_auto_alloc_size = sizeof(struct sandbox_clk_test), +}; diff --git a/drivers/clk/exynos/clk-exynos7420.c b/drivers/clk/exynos/clk-exynos7420.c index bf5d0e6e60..1f017a307f 100644 --- a/drivers/clk/exynos/clk-exynos7420.c +++ b/drivers/clk/exynos/clk-exynos7420.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "clk-pll.h" @@ -67,11 +67,11 @@ struct exynos7420_clk_top0_priv { unsigned long sclk_uart2; }; -static ulong exynos7420_topc_get_periph_rate(struct udevice *dev, int periph) +static ulong exynos7420_topc_get_rate(struct clk *clk) { - struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev); + struct exynos7420_clk_topc_priv *priv = dev_get_priv(clk->dev); - switch (periph) { + switch (clk->id) { case DOUT_SCLK_BUS0_PLL: case SCLK_BUS0_PLL_A: case SCLK_BUS0_PLL_B: @@ -86,14 +86,14 @@ static ulong exynos7420_topc_get_periph_rate(struct udevice *dev, int periph) } static struct clk_ops exynos7420_clk_topc_ops = { - .get_periph_rate = exynos7420_topc_get_periph_rate, + .get_rate = exynos7420_topc_get_rate, }; static int exynos7420_clk_topc_probe(struct udevice *dev) { struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev); struct exynos7420_clk_cmu_topc *topc; - struct udevice *clk_dev; + struct clk in_clk; unsigned long rate; fdt_addr_t base; int ret; @@ -105,9 +105,9 @@ static int exynos7420_clk_topc_probe(struct udevice *dev) topc = (struct exynos7420_clk_cmu_topc *)base; priv->topc = topc; - ret = clk_get_by_index(dev, 0, &clk_dev); + ret = clk_get_by_index(dev, 0, &in_clk); if (ret >= 0) - priv->fin_freq = clk_get_rate(clk_dev); + priv->fin_freq = clk_get_rate(&in_clk); rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq); if (readl(&topc->mux_sel[1]) & (1 << 16)) @@ -122,12 +122,12 @@ static int exynos7420_clk_topc_probe(struct udevice *dev) return 0; } -static ulong exynos7420_top0_get_periph_rate(struct udevice *dev, int periph) +static ulong exynos7420_top0_get_rate(struct clk *clk) { - struct exynos7420_clk_top0_priv *priv = dev_get_priv(dev); + struct exynos7420_clk_top0_priv *priv = dev_get_priv(clk->dev); struct exynos7420_clk_cmu_top0 *top0 = priv->top0; - switch (periph) { + switch (clk->id) { case CLK_SCLK_UART2: return priv->mout_top0_bus0_pll_half / DIVIDER(&top0->div_peric[3], 8, 0xf); @@ -137,14 +137,14 @@ static ulong exynos7420_top0_get_periph_rate(struct udevice *dev, int periph) } static struct clk_ops exynos7420_clk_top0_ops = { - .get_periph_rate = exynos7420_top0_get_periph_rate, + .get_rate = exynos7420_top0_get_rate, }; static int exynos7420_clk_top0_probe(struct udevice *dev) { struct exynos7420_clk_top0_priv *priv; struct exynos7420_clk_cmu_top0 *top0; - struct udevice *clk_dev; + struct clk in_clk; fdt_addr_t base; int ret; @@ -159,10 +159,10 @@ static int exynos7420_clk_top0_probe(struct udevice *dev) top0 = (struct exynos7420_clk_cmu_top0 *)base; priv->top0 = top0; - ret = clk_get_by_index(dev, 1, &clk_dev); + ret = clk_get_by_index(dev, 1, &in_clk); if (ret >= 0) { priv->mout_top0_bus0_pll_half = - clk_get_periph_rate(clk_dev, ret); + clk_get_rate(&in_clk); if (readl(&top0->mux_sel[1]) & (1 << 16)) priv->mout_top0_bus0_pll_half >>= 1; } @@ -170,18 +170,18 @@ static int exynos7420_clk_top0_probe(struct udevice *dev) return 0; } -static ulong exynos7420_peric1_get_periph_rate(struct udevice *dev, int periph) +static ulong exynos7420_peric1_get_rate(struct clk *clk) { - struct udevice *clk_dev; + struct clk in_clk; unsigned int ret; unsigned long freq = 0; - switch (periph) { + switch (clk->id) { case SCLK_UART2: - ret = clk_get_by_index(dev, 3, &clk_dev); + ret = clk_get_by_index(clk->dev, 3, &in_clk); if (ret < 0) return ret; - freq = clk_get_periph_rate(clk_dev, ret); + freq = clk_get_rate(&in_clk); break; } @@ -189,7 +189,7 @@ static ulong exynos7420_peric1_get_periph_rate(struct udevice *dev, int periph) } static struct clk_ops exynos7420_clk_peric1_ops = { - .get_periph_rate = exynos7420_peric1_get_periph_rate, + .get_rate = exynos7420_peric1_get_rate, }; static const struct udevice_id exynos7420_clk_topc_compat[] = { diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index 25c163b395..2f5d4d8391 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -9,14 +9,14 @@ #include #include #include -#include +#include #include #include "clk-uniphier.h" -static int uniphier_clk_enable(struct udevice *dev, int index) +static int uniphier_clk_enable(struct clk *clk) { - struct uniphier_clk_priv *priv = dev_get_priv(dev); + struct uniphier_clk_priv *priv = dev_get_priv(clk->dev); struct uniphier_clk_gate_data *gate = priv->socdata->gate; unsigned int nr_gate = priv->socdata->nr_gate; void __iomem *reg; @@ -24,7 +24,7 @@ static int uniphier_clk_enable(struct udevice *dev, int index) int i; for (i = 0; i < nr_gate; i++) { - if (gate[i].index != index) + if (gate[i].index != clk->id) continue; reg = priv->base + gate[i].reg; @@ -41,9 +41,9 @@ static int uniphier_clk_enable(struct udevice *dev, int index) return 0; } -static ulong uniphier_clk_get_rate(struct udevice *dev, int index) +static ulong uniphier_clk_get_rate(struct clk *clk) { - struct uniphier_clk_priv *priv = dev_get_priv(dev); + struct uniphier_clk_priv *priv = dev_get_priv(clk->dev); struct uniphier_clk_rate_data *rdata = priv->socdata->rate; unsigned int nr_rdata = priv->socdata->nr_rate; void __iomem *reg; @@ -52,7 +52,7 @@ static ulong uniphier_clk_get_rate(struct udevice *dev, int index) int i; for (i = 0; i < nr_rdata; i++) { - if (rdata[i].index != index) + if (rdata[i].index != clk->id) continue; if (rdata[i].reg == UNIPHIER_CLK_RATE_IS_FIXED) @@ -75,9 +75,9 @@ static ulong uniphier_clk_get_rate(struct udevice *dev, int index) return matched_rate; } -static ulong uniphier_clk_set_rate(struct udevice *dev, int index, ulong rate) +static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate) { - struct uniphier_clk_priv *priv = dev_get_priv(dev); + struct uniphier_clk_priv *priv = dev_get_priv(clk->dev); struct uniphier_clk_rate_data *rdata = priv->socdata->rate; unsigned int nr_rdata = priv->socdata->nr_rate; void __iomem *reg; @@ -87,7 +87,7 @@ static ulong uniphier_clk_set_rate(struct udevice *dev, int index, ulong rate) /* first, decide the best match rate */ for (i = 0; i < nr_rdata; i++) { - if (rdata[i].index != index) + if (rdata[i].index != clk->id) continue; if (rdata[i].reg == UNIPHIER_CLK_RATE_IS_FIXED) @@ -105,7 +105,7 @@ static ulong uniphier_clk_set_rate(struct udevice *dev, int index, ulong rate) /* second, really set registers */ for (i = 0; i < nr_rdata; i++) { - if (rdata[i].index != index || rdata[i].rate != best_rate) + if (rdata[i].index != clk->id || rdata[i].rate != best_rate) continue; reg = priv->base + rdata[i].reg; @@ -124,8 +124,8 @@ static ulong uniphier_clk_set_rate(struct udevice *dev, int index, ulong rate) const struct clk_ops uniphier_clk_ops = { .enable = uniphier_clk_enable, - .get_periph_rate = uniphier_clk_get_rate, - .set_periph_rate = uniphier_clk_set_rate, + .get_rate = uniphier_clk_get_rate, + .set_rate = uniphier_clk_set_rate, }; int uniphier_clk_probe(struct udevice *dev) diff --git a/drivers/clk/uniphier/clk-uniphier-mio.c b/drivers/clk/uniphier/clk-uniphier-mio.c index c6ecd119bd..2dd3fc074a 100644 --- a/drivers/clk/uniphier/clk-uniphier-mio.c +++ b/drivers/clk/uniphier/clk-uniphier-mio.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include #include #include "clk-uniphier.h" diff --git a/drivers/i2c/rk_i2c.c b/drivers/i2c/rk_i2c.c index 3fceade61e..63b141838b 100644 --- a/drivers/i2c/rk_i2c.c +++ b/drivers/i2c/rk_i2c.c @@ -29,10 +29,9 @@ DECLARE_GLOBAL_DATA_PTR; #define RK_I2C_FIFO_SIZE 32 struct rk_i2c { - struct udevice *clk; + struct clk clk; struct i2c_regs *regs; unsigned int speed; - int clk_id; }; static inline void rk_i2c_get_div(int div, int *divh, int *divl) @@ -55,7 +54,7 @@ static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate) int div, divl, divh; /* First get i2c rate from pclk */ - i2c_rate = clk_get_periph_rate(i2c->clk, i2c->clk_id); + i2c_rate = clk_get_rate(&i2c->clk); div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2; divh = 0; @@ -362,7 +361,6 @@ static int rockchip_i2c_ofdata_to_platdata(struct udevice *bus) bus->name, ret); return ret; } - priv->clk_id = ret; return 0; } diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index 1e2a29b825..64bbf0cd25 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -49,7 +49,8 @@ static int msm_sdc_clk_init(struct udevice *dev) "clock-frequency", 400000); uint clkd[2]; /* clk_id and clk_no */ int clk_offset; - struct udevice *clk; + struct udevice *clk_dev; + struct clk clk; int ret; ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd, @@ -61,11 +62,17 @@ static int msm_sdc_clk_init(struct udevice *dev) if (clk_offset < 0) return clk_offset; - ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk); + ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev); if (ret) return ret; - ret = clk_set_periph_rate(clk, clkd[1], clk_rate); + clk.id = clkd[1]; + ret = clk_request(clk_dev, &clk); + if (ret < 0) + return ret; + + ret = clk_set_rate(&clk, clk_rate); + clk_free(&clk); if (ret < 0) return ret; diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index 750ab9f8c5..d41d60ce35 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -24,8 +24,7 @@ struct rockchip_mmc_plat { }; struct rockchip_dwmmc_priv { - struct udevice *clk; - int periph; + struct clk clk; struct dwmci_host host; }; @@ -35,7 +34,7 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq) struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); int ret; - ret = clk_set_periph_rate(priv->clk, priv->periph, freq); + ret = clk_set_rate(&priv->clk, freq); if (ret < 0) { debug("%s: err=%d\n", __func__, ret); return ret; @@ -81,7 +80,6 @@ static int rockchip_dwmmc_probe(struct udevice *dev) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; - priv->periph = ret; if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock-freq-min-max", minmax, 2)) diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 4978cca76d..152e987397 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -651,8 +651,7 @@ int uniphier_sd_probe(struct udevice *dev) struct uniphier_sd_priv *priv = dev_get_priv(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); fdt_addr_t base; - struct udevice *clk_dev; - int clk_id; + struct clk clk; int ret; priv->dev = dev; @@ -665,20 +664,22 @@ int uniphier_sd_probe(struct udevice *dev) if (!priv->regbase) return -ENOMEM; - clk_id = clk_get_by_index(dev, 0, &clk_dev); - if (clk_id < 0) { + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) { dev_err(dev, "failed to get host clock\n"); - return clk_id; + return ret; } /* set to max rate */ - priv->mclk = clk_set_periph_rate(clk_dev, clk_id, ULONG_MAX); + priv->mclk = clk_set_rate(&clk, ULONG_MAX); if (IS_ERR_VALUE(priv->mclk)) { dev_err(dev, "failed to set rate for host clock\n"); + clk_free(&clk); return priv->mclk; } - ret = clk_enable(clk_dev, clk_id); + ret = clk_enable(&clk); + clk_free(&clk); if (ret) { dev_err(dev, "failed to enable host clock\n"); return ret; diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index 80fb89ea8b..a7cab1346f 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -150,7 +150,8 @@ static int msm_uart_clk_init(struct udevice *dev) "clock-frequency", 115200); uint clkd[2]; /* clk_id and clk_no */ int clk_offset; - struct udevice *clk; + struct udevice *clk_dev; + struct clk clk; int ret; ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, "clock", clkd, @@ -162,11 +163,17 @@ static int msm_uart_clk_init(struct udevice *dev) if (clk_offset < 0) return clk_offset; - ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk); + ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev); if (ret) return ret; - ret = clk_set_periph_rate(clk, clkd[1], clk_rate); + clk.id = clkd[1]; + ret = clk_request(clk_dev, &clk); + if (ret < 0) + return ret; + + ret = clk_set_rate(&clk, clk_rate); + clk_free(&clk); if (ret < 0) return ret; diff --git a/drivers/serial/serial_pic32.c b/drivers/serial/serial_pic32.c index af9fbbf655..c2141f0a08 100644 --- a/drivers/serial/serial_pic32.c +++ b/drivers/serial/serial_pic32.c @@ -135,7 +135,7 @@ static int pic32_uart_getc(struct udevice *dev) static int pic32_uart_probe(struct udevice *dev) { struct pic32_uart_priv *priv = dev_get_priv(dev); - struct udevice *clkdev; + struct clk clk; fdt_addr_t addr; fdt_size_t size; int ret; @@ -148,10 +148,11 @@ static int pic32_uart_probe(struct udevice *dev) priv->base = ioremap(addr, size); /* get clock rate */ - ret = clk_get_by_index(dev, 0, &clkdev); + ret = clk_get_by_index(dev, 0, &clk); if (ret < 0) return ret; - priv->uartclk = clk_get_periph_rate(clkdev, ret); + priv->uartclk = clk_get_rate(&clk); + clk_free(&clk); /* initialize serial */ return pic32_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE); diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index cb55c5ab71..622547951e 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -94,13 +94,13 @@ int s5p_serial_setbrg(struct udevice *dev, int baudrate) u32 uclk; #ifdef CONFIG_CLK_EXYNOS - struct udevice *clk_dev; + struct clk clk; u32 ret; - ret = clk_get_by_index(dev, 1, &clk_dev); + ret = clk_get_by_index(dev, 1, &clk); if (ret < 0) return ret; - uclk = clk_get_periph_rate(clk_dev, ret); + uclk = clk_get_rate(&clk); #else uclk = get_uart_clk(plat->port_id); #endif diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c index 9eff423acd..bc6dfd8862 100644 --- a/drivers/spi/rk_spi.c +++ b/drivers/spi/rk_spi.c @@ -35,8 +35,7 @@ struct rockchip_spi_platdata { struct rockchip_spi_priv { struct rockchip_spi *regs; - struct udevice *clk; - int clk_id; + struct clk clk; unsigned int max_freq; unsigned int mode; ulong last_transaction_us; /* Time of last transaction end */ @@ -144,7 +143,6 @@ static int rockchip_spi_ofdata_to_platdata(struct udevice *bus) bus->name, ret); return ret; } - priv->clk_id = ret; plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", 50000000); @@ -175,7 +173,7 @@ static int rockchip_spi_probe(struct udevice *bus) * Use 99 MHz as our clock since it divides nicely into 594 MHz which * is the assumed speed for CLK_GENERAL. */ - ret = clk_set_periph_rate(priv->clk, priv->clk_id, 99000000); + ret = clk_set_rate(&priv->clk, 99000000); if (ret < 0) { debug("%s: Failed to set clock: %d\n", __func__, ret); return ret; diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index 4444988e36..e0377ca1c9 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -26,15 +26,15 @@ static int ehci_usb_probe(struct udevice *dev) int i; for (i = 0; ; i++) { - struct udevice *clk_dev; - int clk_id; + struct clk clk; + int ret; - clk_id = clk_get_by_index(dev, i, &clk_dev); - if (clk_id < 0) + ret = clk_get_by_index(dev, i, &clk); + if (ret < 0) break; - if (clk_enable(clk_dev, clk_id)) - printf("failed to enable clock (dev=%s, id=%d)\n", - clk_dev->name, clk_id); + if (clk_enable(&clk)) + printf("failed to enable clock %d\n", i); + clk_free(&clk); } hccr = map_physmem(dev_get_addr(dev), 0x100, MAP_NOCACHE); diff --git a/drivers/video/rockchip/rk_edp.c b/drivers/video/rockchip/rk_edp.c index 124ddf684b..7ece038c8f 100644 --- a/drivers/video/rockchip/rk_edp.c +++ b/drivers/video/rockchip/rk_edp.c @@ -1009,8 +1009,7 @@ int rk_edp_probe(struct udevice *dev) struct display_plat *uc_plat = dev_get_uclass_platdata(dev); struct rk_edp_priv *priv = dev_get_priv(dev); struct rk3288_edp *regs = priv->regs; - struct udevice *clk; - int periph; + struct clk clk; int ret; ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel", @@ -1026,8 +1025,8 @@ int rk_edp_probe(struct udevice *dev) ret = clk_get_by_index(dev, 1, &clk); if (ret >= 0) { - periph = ret; - ret = clk_set_periph_rate(clk, periph, 0); + ret = clk_set_rate(&clk, 0); + clk_free(&clk); } if (ret) { debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret); @@ -1036,8 +1035,8 @@ int rk_edp_probe(struct udevice *dev) ret = clk_get_by_index(uc_plat->src_dev, 0, &clk); if (ret >= 0) { - periph = ret; - ret = clk_set_periph_rate(clk, periph, 192000000); + ret = clk_set_rate(&clk, 192000000); + clk_free(&clk); } if (ret < 0) { debug("%s: Failed to set clock in source device '%s': ret=%d\n", diff --git a/drivers/video/rockchip/rk_hdmi.c b/drivers/video/rockchip/rk_hdmi.c index 5fcb61ac2a..8dd2c87090 100644 --- a/drivers/video/rockchip/rk_hdmi.c +++ b/drivers/video/rockchip/rk_hdmi.c @@ -859,15 +859,15 @@ static int rk_hdmi_probe(struct udevice *dev) { struct display_plat *uc_plat = dev_get_uclass_platdata(dev); struct rk_hdmi_priv *priv = dev_get_priv(dev); - struct udevice *reg, *clk; - int periph; + struct udevice *reg; + struct clk clk; int ret; int vop_id = uc_plat->source_id; ret = clk_get_by_index(dev, 0, &clk); if (ret >= 0) { - periph = ret; - ret = clk_set_periph_rate(clk, periph, 0); + ret = clk_set_rate(&clk, 0); + clk_free(&clk); } if (ret) { debug("%s: Failed to set EDP clock: ret=%d\n", __func__, ret); @@ -880,8 +880,8 @@ static int rk_hdmi_probe(struct udevice *dev) */ ret = clk_get_by_index(uc_plat->src_dev, 0, &clk); if (ret >= 0) { - periph = ret; - ret = clk_set_periph_rate(clk, periph, 384000000); + ret = clk_set_rate(&clk, 384000000); + clk_free(&clk); } if (ret < 0) { debug("%s: Failed to set clock in source device '%s': ret=%d\n", diff --git a/drivers/video/rockchip/rk_lvds.c b/drivers/video/rockchip/rk_lvds.c index dc10b866c9..fcbb4d63d2 100644 --- a/drivers/video/rockchip/rk_lvds.c +++ b/drivers/video/rockchip/rk_lvds.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c index db09d9a41d..cc26f1956d 100644 --- a/drivers/video/rockchip/rk_vop.c +++ b/drivers/video/rockchip/rk_vop.c @@ -195,7 +195,8 @@ int rk_display_init(struct udevice *dev, ulong fbbase, struct udevice *disp; int ret, remote, i, offset; struct display_plat *disp_uc_plat; - struct udevice *clk; + struct udevice *dev_clk; + struct clk clk; vop_id = fdtdec_get_int(blob, ep_node, "reg", -1); debug("vop_id=%d\n", vop_id); @@ -237,11 +238,13 @@ int rk_display_init(struct udevice *dev, ulong fbbase, return ret; } - ret = rkclk_get_clk(CLK_NEW, &clk); + ret = uclass_get_device(UCLASS_CLK, 0, &dev_clk); if (!ret) { - ret = clk_set_periph_rate(clk, DCLK_VOP0 + remote_vop_id, - timing.pixelclock.typ); + clk.id = DCLK_VOP0 + remote_vop_id; + ret = clk_request(dev_clk, &clk); } + if (!ret) + ret = clk_set_rate(&clk, timing.pixelclock.typ); if (ret) { debug("%s: Failed to set pixel clock: ret=%d\n", __func__, ret); return ret; diff --git a/include/clk-uclass.h b/include/clk-uclass.h new file mode 100644 index 0000000000..07c1065495 --- /dev/null +++ b/include/clk-uclass.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * Copyright (c) 2016, NVIDIA CORPORATION. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _CLK_UCLASS_H +#define _CLK_UCLASS_H + +/* See clk.h for background documentation. */ + +#include +#include + +/** + * struct clk_ops - The functions that a clock driver must implement. + */ +struct clk_ops { + /** + * of_xlate - Translate a client's device-tree (OF) clock specifier. + * + * The clock core calls this function as the first step in implementing + * a client's clk_get_by_*() call. + * + * If this function pointer is set to NULL, the clock core will use a + * default implementation, which assumes #clock-cells = <1>, and that + * the DT cell contains a simple integer clock ID. + * + * At present, the clock API solely supports device-tree. If this + * changes, other xxx_xlate() functions may be added to support those + * other mechanisms. + * + * @clock: The clock struct to hold the translation result. + * @args: The clock specifier values from device tree. + * @return 0 if OK, or a negative error code. + */ + int (*of_xlate)(struct clk *clock, + struct fdtdec_phandle_args *args); + /** + * request - Request a translated clock. + * + * The clock core calls this function as the second step in + * implementing a client's clk_get_by_*() call, following a successful + * xxx_xlate() call, or as the only step in implementing a client's + * clk_request() call. + * + * @clock: The clock struct to request; this has been fille in by + * a previoux xxx_xlate() function call, or by the caller + * of clk_request(). + * @return 0 if OK, or a negative error code. + */ + int (*request)(struct clk *clock); + /** + * free - Free a previously requested clock. + * + * This is the implementation of the client clk_free() API. + * + * @clock: The clock to free. + * @return 0 if OK, or a negative error code. + */ + int (*free)(struct clk *clock); + /** + * get_rate() - Get current clock rate. + * + * @clk: The clock to query. + * @return clock rate in Hz, or -ve error code + */ + ulong (*get_rate)(struct clk *clk); + /** + * set_rate() - Set current clock rate. + * + * @clk: The clock to manipulate. + * @rate: New clock rate in Hz. + * @return new rate, or -ve error code. + */ + ulong (*set_rate)(struct clk *clk, ulong rate); + /** + * enable() - Enable a clock. + * + * @clk: The clock to manipulate. + * @return zero on success, or -ve error code. + */ + int (*enable)(struct clk *clk); + /** + * disable() - Disable a clock. + * + * @clk: The clock to manipulate. + * @return zero on success, or -ve error code. + */ + int (*disable)(struct clk *clk); +}; + +#endif diff --git a/include/clk.h b/include/clk.h index ca20c3dd27..2f31cf70e3 100644 --- a/include/clk.h +++ b/include/clk.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2015 Google, Inc * Written by Simon Glass + * Copyright (c) 2016, NVIDIA CORPORATION. * * SPDX-License-Identifier: GPL-2.0+ */ @@ -8,125 +9,166 @@ #ifndef _CLK_H_ #define _CLK_H_ -#include #include -struct udevice; +/** + * A clock is a hardware signal that oscillates autonomously at a specific + * frequency and duty cycle. Most hardware modules require one or more clock + * signal to drive their operation. Clock signals are typically generated + * externally to the HW module consuming them, by an entity this API calls a + * clock provider. This API provides a standard means for drivers to enable and + * disable clocks, and to set the rate at which they oscillate. + * + * A driver that implements UCLASS_CLOCK is a clock provider. A provider will + * often implement multiple separate clocks, since the hardware it manages + * often has this capability. clock_uclass.h describes the interface which + * clock providers must implement. + * + * Clock consumers/clients are the HW modules driven by the clock signals. This + * header file describes the API used by drivers for those HW modules. + */ -int soc_clk_dump(void); +struct udevice; -struct clk_ops { - /** - * get_rate() - Get current clock rate - * - * @dev: Device to check (UCLASS_CLK) - * @return clock rate in Hz, or -ve error code - */ - ulong (*get_rate)(struct udevice *dev); - - /** - * set_rate() - Set current clock rate - * - * @dev: Device to adjust - * @rate: New clock rate in Hz - * @return new rate, or -ve error code - */ - ulong (*set_rate)(struct udevice *dev, ulong rate); - - /** - * enable() - Enable the clock for a peripheral - * - * @dev: clock provider - * @periph: Peripheral ID to enable - * @return zero on success, or -ve error code - */ - int (*enable)(struct udevice *dev, int periph); - - /** - * get_periph_rate() - Get clock rate for a peripheral - * - * @dev: Device to check (UCLASS_CLK) - * @periph: Peripheral ID to check - * @return clock rate in Hz, or -ve error code - */ - ulong (*get_periph_rate)(struct udevice *dev, int periph); - - /** - * set_periph_rate() - Set current clock rate for a peripheral - * - * @dev: Device to update (UCLASS_CLK) - * @periph: Peripheral ID to update - * @return new clock rate in Hz, or -ve error code +/** + * struct clk - A handle to (allowing control of) a single clock. + * + * Clients provide storage for clock handles. The content of the structure is + * managed solely by the clock API and clock drivers. A clock struct is + * initialized by "get"ing the clock struct. The clock struct is passed to all + * other clock APIs to identify which clock signal to operate upon. + * + * @dev: The device which implements the clock signal. + * @id: The clock signal ID within the provider. + * + * Currently, the clock API assumes that a single integer ID is enough to + * identify and configure any clock signal for any clock provider. If this + * assumption becomes invalid in the future, the struct could be expanded to + * either (a) add more fields to allow clock providers to store additional + * information, or (b) replace the id field with an opaque pointer, which the + * provider would dynamically allocated during its .of_xlate op, and process + * during is .request op. This may require the addition of an extra op to clean + * up the allocation. + */ +struct clk { + struct udevice *dev; + /* + * Written by of_xlate. We assume a single id is enough for now. In the + * future, we might add more fields here. */ - ulong (*set_periph_rate)(struct udevice *dev, int periph, ulong rate); + unsigned long id; }; -#define clk_get_ops(dev) ((struct clk_ops *)(dev)->driver->ops) +#if CONFIG_IS_ENABLED(OF_CONTROL) +/** + * clock_get_by_index - Get/request a clock by integer index. + * + * This looks up and requests a clock. The index is relative to the client + * device; each device is assumed to have n clocks associated with it somehow, + * and this function finds and requests one of them. The mapping of client + * device clock indices to provider clocks may be via device-tree properties, + * board-provided mapping tables, or some other mechanism. + * + * @dev: The client device. + * @index: The index of the clock to request, within the client's list of + * clocks. + * @clock A pointer to a clock struct to initialize. + * @return 0 if OK, or a negative error code. + */ +int clk_get_by_index(struct udevice *dev, int index, struct clk *clk); /** - * clk_get_rate() - Get current clock rate + * clock_get_by_name - Get/request a clock by name. * - * @dev: Device to check (UCLASS_CLK) - * @return clock rate in Hz, or -ve error code + * This looks up and requests a clock. The name is relative to the client + * device; each device is assumed to have n clocks associated with it somehow, + * and this function finds and requests one of them. The mapping of client + * device clock names to provider clocks may be via device-tree properties, + * board-provided mapping tables, or some other mechanism. + * + * @dev: The client device. + * @name: The name of the clock to request, within the client's list of + * clocks. + * @clock: A pointer to a clock struct to initialize. + * @return 0 if OK, or a negative error code. */ -ulong clk_get_rate(struct udevice *dev); +int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk); +#else +static inline int clk_get_by_index(struct udevice *dev, int index, + struct clk *clk) +{ + return -ENOSYS; +} + +static int clk_get_by_name(struct udevice *dev, const char *name, + struct clk *clk) +{ + return -ENOSYS; +} +#endif /** - * clk_set_rate() - Set current clock rate + * clk_request - Request a clock by provider-specific ID. * - * @dev: Device to adjust - * @rate: New clock rate in Hz - * @return new rate, or -ve error code + * This requests a clock using a provider-specific ID. Generally, this function + * should not be used, since clk_get_by_index/name() provide an interface that + * better separates clients from intimate knowledge of clock providers. + * However, this function may be useful in core SoC-specific code. + * + * @dev: The clock provider device. + * @clock: A pointer to a clock struct to initialize. The caller must + * have already initialized any field in this struct which the + * clock provider uses to identify the clock. + * @return 0 if OK, or a negative error code. */ -ulong clk_set_rate(struct udevice *dev, ulong rate); +int clk_request(struct udevice *dev, struct clk *clk); /** - * clk_enable() - Enable the clock for a peripheral + * clock_free - Free a previously requested clock. * - * @dev: clock provider - * @periph: Peripheral ID to enable - * @return zero on success, or -ve error code + * @clock: A clock struct that was previously successfully requested by + * clk_request/get_by_*(). + * @return 0 if OK, or a negative error code. */ -int clk_enable(struct udevice *dev, int periph); +int clk_free(struct clk *clk); /** - * clk_get_periph_rate() - Get current clock rate for a peripheral + * clk_get_rate() - Get current clock rate. * - * @dev: Device to check (UCLASS_CLK) - * @return clock rate in Hz, -ve error code + * @clk: A clock struct that was previously successfully requested by + * clk_request/get_by_*(). + * @return clock rate in Hz, or -ve error code. */ -ulong clk_get_periph_rate(struct udevice *dev, int periph); +ulong clk_get_rate(struct clk *clk); /** - * clk_set_periph_rate() - Set current clock rate for a peripheral + * clk_set_rate() - Set current clock rate. * - * @dev: Device to update (UCLASS_CLK) - * @periph: Peripheral ID to update - * @return new clock rate in Hz, or -ve error code + * @clk: A clock struct that was previously successfully requested by + * clk_request/get_by_*(). + * @rate: New clock rate in Hz. + * @return new rate, or -ve error code. */ -ulong clk_set_periph_rate(struct udevice *dev, int periph, ulong rate); +ulong clk_set_rate(struct clk *clk, ulong rate); -#if CONFIG_IS_ENABLED(OF_CONTROL) /** - * clk_get_by_index() - look up a clock referenced by a device + * clk_enable() - Enable (turn on) a clock. * - * Parse a device's 'clocks' list, returning information on the indexed clock, - * ensuring that it is activated. + * @clk: A clock struct that was previously successfully requested by + * clk_request/get_by_*(). + * @return zero on success, or -ve error code. + */ +int clk_enable(struct clk *clk); + +/** + * clk_disable() - Disable (turn off) a clock. * - * @dev: Device containing the clock reference - * @index: Clock index to return (0 = first) - * @clk_devp: Returns clock device - * @return: Peripheral ID for the device to control. This is the first - * argument after the clock node phandle. If there is no arguemnt, - * returns 0. Return -ve error code on any error + * @clk: A clock struct that was previously successfully requested by + * clk_request/get_by_*(). + * @return zero on success, or -ve error code. */ -int clk_get_by_index(struct udevice *dev, int index, struct udevice **clk_devp); -#else -static inline int clk_get_by_index(struct udevice *dev, int index, - struct udevice **clk_devp) -{ - return -ENOSYS; -} -#endif +int clk_disable(struct clk *clk); -#endif /* _CLK_H_ */ +int soc_clk_dump(void); + +#endif diff --git a/test/dm/clk.c b/test/dm/clk.c index 9ff6d95103..712a1e674a 100644 --- a/test/dm/clk.c +++ b/test/dm/clk.c @@ -5,55 +5,99 @@ */ #include -#include #include -#include +#include #include #include #include -/* Test that we can find and adjust clocks */ -static int dm_test_clk_base(struct unit_test_state *uts) +static int dm_test_clk(struct unit_test_state *uts) { - struct udevice *clk; + struct udevice *dev_fixed, *dev_clk, *dev_test; ulong rate; - ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk)); - rate = clk_get_rate(clk); - ut_asserteq(SANDBOX_CLK_RATE, rate); - ut_asserteq(-EINVAL, clk_set_rate(clk, 0)); - ut_assertok(clk_set_rate(clk, rate * 2)); - ut_asserteq(SANDBOX_CLK_RATE * 2, clk_get_rate(clk)); + ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-fixed", + &dev_fixed)); - return 0; -} -DM_TEST(dm_test_clk_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + ut_assertok(uclass_get_device_by_name(UCLASS_CLK, "clk-sbox", + &dev_clk)); + ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI)); + ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C)); + ut_asserteq(0, sandbox_clk_query_rate(dev_clk, SANDBOX_CLK_ID_SPI)); + ut_asserteq(0, sandbox_clk_query_rate(dev_clk, SANDBOX_CLK_ID_I2C)); -/* Test that peripheral clocks work as expected */ -static int dm_test_clk_periph(struct unit_test_state *uts) -{ - struct udevice *clk; - ulong rate; + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "clk-test", + &dev_test)); + ut_assertok(sandbox_clk_test_get(dev_test)); - ut_assertok(uclass_get_device(UCLASS_CLK, 0, &clk)); - rate = clk_set_periph_rate(clk, PERIPH_ID_COUNT, 123); - ut_asserteq(-EINVAL, rate); - ut_asserteq(1, IS_ERR_VALUE(rate)); + ut_asserteq(1234, + sandbox_clk_test_get_rate(dev_test, + SANDBOX_CLK_TEST_ID_FIXED)); + ut_asserteq(0, sandbox_clk_test_get_rate(dev_test, + SANDBOX_CLK_TEST_ID_SPI)); + ut_asserteq(0, sandbox_clk_test_get_rate(dev_test, + SANDBOX_CLK_TEST_ID_I2C)); - rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 123); - ut_asserteq(0, rate); - ut_asserteq(123, clk_get_periph_rate(clk, PERIPH_ID_SPI)); + rate = sandbox_clk_test_set_rate(dev_test, SANDBOX_CLK_TEST_ID_FIXED, + 12345); + ut_assert(IS_ERR_VALUE(rate)); + rate = sandbox_clk_test_get_rate(dev_test, SANDBOX_CLK_TEST_ID_FIXED); + ut_asserteq(1234, rate); - rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234); - ut_asserteq(123, rate); + ut_asserteq(0, sandbox_clk_test_set_rate(dev_test, + SANDBOX_CLK_TEST_ID_SPI, + 1000)); + ut_asserteq(0, sandbox_clk_test_set_rate(dev_test, + SANDBOX_CLK_TEST_ID_I2C, + 2000)); - rate = clk_set_periph_rate(clk, PERIPH_ID_I2C, 567); + ut_asserteq(1000, sandbox_clk_test_get_rate(dev_test, + SANDBOX_CLK_TEST_ID_SPI)); + ut_asserteq(2000, sandbox_clk_test_get_rate(dev_test, + SANDBOX_CLK_TEST_ID_I2C)); - rate = clk_set_periph_rate(clk, PERIPH_ID_SPI, 1234); - ut_asserteq(1234, rate); + ut_asserteq(1000, sandbox_clk_test_set_rate(dev_test, + SANDBOX_CLK_TEST_ID_SPI, + 10000)); + ut_asserteq(2000, sandbox_clk_test_set_rate(dev_test, + SANDBOX_CLK_TEST_ID_I2C, + 20000)); + + rate = sandbox_clk_test_set_rate(dev_test, SANDBOX_CLK_TEST_ID_SPI, 0); + ut_assert(IS_ERR_VALUE(rate)); + rate = sandbox_clk_test_set_rate(dev_test, SANDBOX_CLK_TEST_ID_I2C, 0); + ut_assert(IS_ERR_VALUE(rate)); + + ut_asserteq(10000, sandbox_clk_test_get_rate(dev_test, + SANDBOX_CLK_TEST_ID_SPI)); + ut_asserteq(20000, sandbox_clk_test_get_rate(dev_test, + SANDBOX_CLK_TEST_ID_I2C)); + + ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI)); + ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C)); + ut_asserteq(10000, sandbox_clk_query_rate(dev_clk, SANDBOX_CLK_ID_SPI)); + ut_asserteq(20000, sandbox_clk_query_rate(dev_clk, SANDBOX_CLK_ID_I2C)); + + ut_assertok(sandbox_clk_test_enable(dev_test, SANDBOX_CLK_TEST_ID_SPI)); + ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI)); + ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C)); + + ut_assertok(sandbox_clk_test_enable(dev_test, SANDBOX_CLK_TEST_ID_I2C)); + ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI)); + ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C)); + + ut_assertok(sandbox_clk_test_disable(dev_test, + SANDBOX_CLK_TEST_ID_SPI)); + ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI)); + ut_asserteq(1, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C)); + + ut_assertok(sandbox_clk_test_disable(dev_test, + SANDBOX_CLK_TEST_ID_I2C)); + ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_SPI)); + ut_asserteq(0, sandbox_clk_query_enable(dev_clk, SANDBOX_CLK_ID_I2C)); - ut_asserteq(567, clk_get_periph_rate(clk, PERIPH_ID_I2C)); + ut_assertok(sandbox_clk_test_free(dev_test)); return 0; } -DM_TEST(dm_test_clk_periph, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); +DM_TEST(dm_test_clk, DM_TESTF_SCAN_FDT); -- cgit v1.2.1