Date: Wed, 13 Jun 2012 20:52:58 +0000 From: aleek@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r237628 - in soc2012/aleek/beaglexm-armv6/sys: arm/ti/am37x boot/fdt/dts Message-ID: <20120613205258.42647106564A@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: aleek Date: Wed Jun 13 20:52:57 2012 New Revision: 237628 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=237628 Log: started to bringing up PRCM for omap3/am37x Modified: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_prcm.c soc2012/aleek/beaglexm-armv6/sys/boot/fdt/dts/beagleboardxm.dts Modified: soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_prcm.c ============================================================================== --- soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_prcm.c Wed Jun 13 19:53:29 2012 (r237627) +++ soc2012/aleek/beaglexm-armv6/sys/arm/ti/am37x/am37x_prcm.c Wed Jun 13 20:52:57 2012 (r237628) @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> + * Copyright (c) 2011 + * Ben Gray <ben.r.gray@gmail.com>. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,10 +12,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -29,130 +30,230 @@ #include <sys/param.h> #include <sys/systm.h> -#include <sys/bus.h> #include <sys/kernel.h> #include <sys/module.h> -#include <sys/malloc.h> +#include <sys/bus.h> +#include <sys/resource.h> #include <sys/rman.h> -#include <sys/timeet.h> -#include <sys/timetc.h> -#include <sys/watchdog.h> +#include <sys/lock.h> +#include <sys/malloc.h> + #include <machine/bus.h> #include <machine/cpu.h> +#include <machine/cpufunc.h> #include <machine/frame.h> +#include <machine/resource.h> #include <machine/intr.h> #include <arm/ti/tivar.h> -#include <arm/ti/ti_scm.h> #include <arm/ti/ti_prcm.h> +#include <arm/ti/am37x/am37x_reg.h> -#include <dev/fdt/fdt_common.h> -#include <dev/ofw/openfirm.h> -#include <dev/ofw/ofw_bus.h> -#include <dev/ofw/ofw_bus_subr.h> -#include <machine/bus.h> -#include <machine/fdt.h> -#define CM_PER 0 -#define CM_PER_L4LS_CLKSTCTRL (CM_PER + 0x000) -#define CM_PER_L3S_CLKSTCTRL (CM_PER + 0x004) -#define CM_PER_L3_CLKSTCTRL (CM_PER + 0x00C) -#define CM_PER_CPGMAC0_CLKCTRL (CM_PER + 0x014) -#define CM_PER_USB0_CLKCTRL (CM_PER + 0x01C) -#define CM_PER_TPTC0_CLKCTRL (CM_PER + 0x024) -#define CM_PER_MMC0_CLKCTRL (CM_PER + 0x03C) -#define CM_PER_I2C2_CLKCTRL (CM_PER + 0x044) -#define CM_PER_I2C1_CLKCTRL (CM_PER + 0x048) -#define CM_PER_TIMER7_CLKCTRL (CM_PER + 0x07C) -#define CM_PER_TIMER2_CLKCTRL (CM_PER + 0x080) -#define CM_PER_TIMER3_CLKCTRL (CM_PER + 0x084) -#define CM_PER_TIMER4_CLKCTRL (CM_PER + 0x088) -#define CM_PER_GPIO1_CLKCTRL (CM_PER + 0x0AC) -#define CM_PER_GPIO2_CLKCTRL (CM_PER + 0x0B0) -#define CM_PER_GPIO3_CLKCTRL (CM_PER + 0x0B4) -#define CM_PER_TPCC_CLKCTRL (CM_PER + 0x0BC) -#define CM_PER_L3_INSTR_CLKCTRL (CM_PER + 0x0DC) -#define CM_PER_L3_CLKCTRL (CM_PER + 0x0E0) -#define CM_PER_TIMER5_CLKCTRL (CM_PER + 0x0EC) -#define CM_PER_TIMER6_CLKCTRL (CM_PER + 0x0F0) -#define CM_PER_MMC1_CLKCTRL (CM_PER + 0x0F4) -#define CM_PER_MMC2_CLKCTRL (CM_PER + 0x0F8) -#define CM_PER_TPTC1_CLKCTRL (CM_PER + 0x0FC) -#define CM_PER_TPTC2_CLKCTRL (CM_PER + 0x100) -#define CM_PER_OCPWP_L3_CLKSTCTRL (CM_PER + 0x12C) -#define CM_PER_OCPWP_CLKCTRL (CM_PER + 0x130) -#define CM_PER_CPSW_CLKSTCTRL (CM_PER + 0x144) - -#define CM_WKUP 0x400 -#define CM_WKUP_CLKSTCTRL (CM_WKUP + 0x000) -#define CM_WKUP_CONTROL_CLKCTRL (CM_WKUP + 0x004) -#define CM_WKUP_GPIO0_CLKCTRL (CM_WKUP + 0x008) -#define CM_WKUP_CM_L3_AON_CLKSTCTRL (CM_WKUP + 0x01C) -#define CM_WKUP_CM_CLKSEL_DPLL_MPU (CM_WKUP + 0x02C) -#define CM_WKUP_CM_CLKDCOLDO_DPLL_PER (CM_WKUP + 0x07C) -#define CM_WKUP_I2C0_CLKCTRL (CM_WKUP + 0x0B8) - -#define CM_DPLL 0x500 -#define CLKSEL_TIMER7_CLK (CM_DPLL + 0x004) -#define CLKSEL_TIMER2_CLK (CM_DPLL + 0x008) -#define CLKSEL_TIMER3_CLK (CM_DPLL + 0x00C) -#define CLKSEL_TIMER4_CLK (CM_DPLL + 0x010) -#define CLKSEL_TIMER5_CLK (CM_DPLL + 0x018) -#define CLKSEL_TIMER6_CLK (CM_DPLL + 0x01C) - -#define PRM_DEVICE_OFFSET 0xF00 -#define PRM_RSTCTRL (PRM_DEVICE_OFFSET + 0x00) - -struct am335x_prcm_softc { - struct resource * res[2]; - bus_space_tag_t bst; - bus_space_handle_t bsh; -}; +/* + * This file defines the clock configuration for the OMAP3xxx series of + * devices. + * + * How This is Suppose to Work + * =========================== + * - There is a top level omap_prcm module that defines all OMAP SoC drivers + * should use to enable/disable the system clocks regardless of the version + * of OMAP device they are running on. This top level PRCM module is just + * a thin shim to chip specific functions that perform the donkey work of + * configuring the clock - this file is the 'donkey' for OMAP35xx devices. + * + * - The key bit in this file is the omap_clk_devmap array, it's + * used by the omap_prcm driver to determine what clocks are valid and which + * functions to call to manipulate them. + * + * - In essence you just need to define some callbacks for each of the + * clocks and then you're done. + * + * - The other thing worth noting is that when the omap_prcm device + * is registered you typically pass in some memory ranges which are the + * SYS_MEMORY resources. These resources are in turn allocated using + * bus_allocate_resources(...) and the resource handles are passed to all + * individual clock callback handlers. + * + * + * + * + */ -static struct resource_spec am335x_prcm_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { -1, 0 } -}; -static struct am335x_prcm_softc *am335x_prcm_sc = NULL; +void +omap3_clk_init(device_t dev, int prio); -static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev); -static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev); -static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); -static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq); -static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); -static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); -static void am335x_prcm_reset(void); -static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev); -static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev); +static int +omap3_clk_generic_activate(const struct ti_clock_dev *clkdev, + struct resource* mem_res[]); + +static int +omap3_clk_generic_deactivate(const struct ti_clock_dev *clkdev, + struct resource* mem_res[]); + +static int +omap3_clk_generic_accessible(const struct ti_clock_dev *clkdev, + struct resource* mem_res[]); + +static int +omap3_clk_generic_set_source(const struct ti_clock_dev *clkdev, clk_src_t clksrc, + struct resource* mem_res[]); + +static int +omap3_clk_generic_get_source_freq(const struct ti_clock_dev *clkdev, + unsigned int *freq, + struct resource* mem_res[]); + + +static int +omap3_clk_gptimer_get_source_freq(const struct ti_clock_dev *clkdev, + unsigned int *freq, + struct resource* mem_res[]); +static int +omap3_clk_gptimer_set_source(const struct ti_clock_dev *clkdev, + clk_src_t clksrc, struct resource* mem_res[]); + + + +static int +omap3_clk_alwayson_null_func(const struct ti_clock_dev *clkdev, + struct resource* mem_res[]); -#define AM335X_GENERIC_CLOCK_DEV(i) \ + + +static int +omap3_clk_get_sysclk_freq(const struct ti_clock_dev *clkdev, + unsigned int *freq, struct resource* mem_res[]); + +static int +omap3_clk_get_arm_fclk_freq(const struct ti_clock_dev *clkdev, + unsigned int *freq, struct resource* mem_res[]); + + + +static int +omap3_clk_hsusbhost_activate(const struct ti_clock_dev *clkdev, + struct resource* mem_res[]); + +static int +omap3_clk_hsusbhost_deactivate(const struct ti_clock_dev *clkdev, + struct resource* mem_res[]); + + + + +#define FREQ_96MHZ 96000000 +#define FREQ_64MHZ 64000000 +#define FREQ_48MHZ 48000000 +#define FREQ_32KHZ 32000 + + + +/** + * Only one memory regions is needed for OMAP35xx clock control (unlike OMAP4) + * + * CM Instance - 0x4800 4000 : 0x4800 5500 + * PRM Instance - 0x4830 6000 : 0x4830 8000 + * + */ +#define CM_INSTANCE_MEM_REGION 0 +#define PRM_INSTANCE_MEM_REGION 1 + +#define IVA2_CM_OFFSET 0x0000 +#define OCP_SYSTEM_CM_OFFSET 0x0800 +#define MPU_CM_OFFSET 0x0900 +#define CORE_CM_OFFSET 0x0A00 +#define SGX_CM_OFFSET 0x0B00 +#define WKUP_CM_OFFSET 0x0C00 +#define CLOCK_CTRL_CM_OFFSET 0x0D00 +#define DSS_CM_OFFSET 0x0E00 +#define CAM_CM_OFFSET 0x0F00 +#define PER_CM_OFFSET 0x1000 +#define EMU_CM_OFFSET 0x1100 +#define GLOBAL_CM_OFFSET 0x1200 +#define NEON_CM_OFFSET 0x1300 +#define USBHOST_CM_OFFSET 0x1400 + +#define IVA2_PRM_OFFSET 0x0000 +#define OCP_SYSTEM_PRM_OFFSET 0x0800 +#define MPU_PRM_OFFSET 0x0900 +#define CORE_PRM_OFFSET 0x0A00 +#define SGX_PRM_OFFSET 0x0B00 +#define WKUP_PRM_OFFSET 0x0C00 +#define CLOCK_CTRL_PRM_OFFSET 0x0D00 +#define DSS_PRM_OFFSET 0x0E00 +#define CAM_PRM_OFFSET 0x0F00 +#define PER_PRM_OFFSET 0x1000 +#define EMU_PRM_OFFSET 0x1100 +#define GLOBAL_PRM_OFFSET 0x1200 +#define NEON_PRM_OFFSET 0x1300 +#define USBHOST_PRM_OFFSET 0x1400 + + + + + + +/** + * omap_clk_devmap - Array of clock devices available on OMAP3xxx devices + * + * This map only defines which clocks are valid and the callback functions + * for clock activate, deactivate, etc. It is used by the top level omap_prcm + * driver. + * + * The actual details of the clocks (config registers, bit fields, sources, + * etc) are in the private g_omap3_clk_details array below. + * + */ + +#define OMAP3_GENERIC_CLOCK_DEV(i) \ { .id = (i), \ - .clk_activate = am335x_clk_generic_activate, \ - .clk_deactivate = am335x_clk_generic_deactivate, \ - .clk_set_source = am335x_clk_generic_set_source, \ - .clk_accessible = NULL, \ + .clk_activate = omap3_clk_generic_activate, \ + .clk_deactivate = omap3_clk_generic_deactivate, \ + .clk_set_source = omap3_clk_generic_set_source, \ + .clk_accessible = omap3_clk_generic_accessible, \ + .clk_get_source_freq = omap3_clk_generic_get_source_freq \ + } + +#define OMAP3_GPTIMER_CLOCK_DEV(i) \ + { .id = (i), \ + .clk_activate = omap3_clk_generic_activate, \ + .clk_deactivate = omap3_clk_generic_deactivate, \ + .clk_set_source = omap3_clk_gptimer_set_source, \ + .clk_accessible = omap3_clk_generic_accessible, \ + .clk_get_source_freq = omap3_clk_gptimer_get_source_freq \ + } + +#define OMAP3_ALWAYSON_CLOCK_DEV(i) \ + { .id = (i), \ + .clk_activate = omap3_clk_alwayson_null_func, \ + .clk_deactivate = omap3_clk_alwayson_null_func, \ + .clk_set_source = NULL, \ + .clk_accessible = omap3_clk_alwayson_null_func, \ .clk_get_source_freq = NULL \ } -#define AM335X_MMCHS_CLOCK_DEV(i) \ +#define OMAP3_HSUSBHOST_CLOCK_DEV(i) \ { .id = (i), \ - .clk_activate = am335x_clk_generic_activate, \ - .clk_deactivate = am335x_clk_generic_deactivate, \ - .clk_set_source = am335x_clk_generic_set_source, \ - .clk_accessible = NULL, \ - .clk_get_source_freq = am335x_clk_hsmmc_get_source_freq \ + .clk_activate = omap3_clk_hsusbhost_activate, \ + .clk_deactivate = omap3_clk_hsusbhost_deactivate, \ + .clk_set_source = NULL, \ + .clk_accessible = omap3_clk_generic_accessible, \ + .clk_get_source_freq = NULL \ } -struct ti_clock_dev ti_clk_devmap[] = { - /* System clocks */ + +const struct ti_clock_dev omap_clk_devmap[] = { + + /* System clock */ { .id = SYS_CLK, .clk_activate = NULL, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, - .clk_get_source_freq = am335x_clk_get_sysclk_freq, + .clk_get_source_freq = omap3_clk_get_sysclk_freq, }, /* MPU (ARM) core clocks */ { .id = MPU_CLK, @@ -160,375 +261,936 @@ .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, - .clk_get_source_freq = am335x_clk_get_arm_fclk_freq, - }, - /* CPSW Ethernet Switch core clocks */ - { .id = CPSW_CLK, - .clk_activate = am335x_clk_cpsw_activate, - .clk_deactivate = NULL, - .clk_set_source = NULL, - .clk_accessible = NULL, - .clk_get_source_freq = NULL, + .clk_get_source_freq = omap3_clk_get_arm_fclk_freq, }, - /* Mentor USB HS controller core clocks */ - { .id = MUSB0_CLK, - .clk_activate = am335x_clk_musb0_activate, - .clk_deactivate = NULL, - .clk_set_source = NULL, - .clk_accessible = NULL, - .clk_get_source_freq = NULL, - }, - /* DMTimer */ - AM335X_GENERIC_CLOCK_DEV(DMTIMER2_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER3_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER4_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER5_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER6_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER7_CLK), + /* UART device clocks */ + OMAP3_GENERIC_CLOCK_DEV(UART1_CLK), + OMAP3_GENERIC_CLOCK_DEV(UART2_CLK), + OMAP3_GENERIC_CLOCK_DEV(UART3_CLK), + OMAP3_GENERIC_CLOCK_DEV(UART4_CLK), + + /* Timer device source clocks */ + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER1_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER2_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER3_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER4_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER5_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER6_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER7_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER8_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER9_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER10_CLK), + OMAP3_GPTIMER_CLOCK_DEV(GPTIMER11_CLK), + + /* MMC device clocks (MMC1 and MMC2 can have different input clocks) */ + OMAP3_GENERIC_CLOCK_DEV(MMC1_CLK), + OMAP3_GENERIC_CLOCK_DEV(MMC2_CLK), + OMAP3_GENERIC_CLOCK_DEV(MMC3_CLK), + + /* USB HS (high speed TLL, EHCI and OHCI) */ + OMAP3_GENERIC_CLOCK_DEV(USBTLL_CLK), + OMAP3_HSUSBHOST_CLOCK_DEV(USBHSHOST_CLK), /* GPIO */ - AM335X_GENERIC_CLOCK_DEV(GPIO0_CLK), - AM335X_GENERIC_CLOCK_DEV(GPIO1_CLK), - AM335X_GENERIC_CLOCK_DEV(GPIO2_CLK), - AM335X_GENERIC_CLOCK_DEV(GPIO3_CLK), - + OMAP3_GENERIC_CLOCK_DEV(GPIO1_CLK), + OMAP3_GENERIC_CLOCK_DEV(GPIO2_CLK), + OMAP3_GENERIC_CLOCK_DEV(GPIO3_CLK), + OMAP3_GENERIC_CLOCK_DEV(GPIO4_CLK), + OMAP3_GENERIC_CLOCK_DEV(GPIO5_CLK), + OMAP3_GENERIC_CLOCK_DEV(GPIO6_CLK), + /* I2C */ - AM335X_GENERIC_CLOCK_DEV(I2C0_CLK), - AM335X_GENERIC_CLOCK_DEV(I2C1_CLK), - AM335X_GENERIC_CLOCK_DEV(I2C2_CLK), - - /* EDMA */ - AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK), - AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK), - AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC1_CLK), - AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC2_CLK), - - /* MMCHS */ - AM335X_MMCHS_CLOCK_DEV(MMC0_CLK), - AM335X_MMCHS_CLOCK_DEV(MMC1_CLK), - AM335X_MMCHS_CLOCK_DEV(MMC2_CLK), + OMAP3_GENERIC_CLOCK_DEV(I2C1_CLK), + OMAP3_GENERIC_CLOCK_DEV(I2C2_CLK), + OMAP3_GENERIC_CLOCK_DEV(I2C3_CLK), + + /* sDMA */ + OMAP3_ALWAYSON_CLOCK_DEV(SDMA_CLK), { INVALID_CLK_IDENT, NULL, NULL, NULL, NULL } }; -struct am335x_clk_details { - clk_ident_t id; - uint32_t clkctrl_reg; - uint32_t clksel_reg; + + + + + +/** + * g_omap3_clk_details - Stores details for all the different clocks supported + * + * Whenever an operation on a clock is being performed (activated, deactivated, + * etc) this array is looked up to find the correct register and bit(s) we + * should be modifying. + * + */ + +struct omap3_clk_details { + clk_ident_t id; + int32_t src_freq; + + /* The register offset from the CM module register region of the registers*/ + uint32_t fclken_offset; + uint32_t iclken_offset; + uint32_t idlest_offset; + + /* The bit offset for the clock */ + uint32_t bit_offset; }; -#define _CLK_DETAIL(i, c, s) \ - { .id = (i), \ - .clkctrl_reg = (c), \ - .clksel_reg = (s), \ +#define OMAP3_GENERIC_CLOCK_DETAILS(d, freq, base, fclk, iclk, idlest, bit) \ + { .id = (d), \ + .src_freq = (freq), \ + .fclken_offset = ((base) + (fclk)), \ + .iclken_offset = ((base) + (iclk)), \ + .idlest_offset = ((base) + (idlest)), \ + .bit_offset = (bit), \ } -static struct am335x_clk_details g_am335x_clk_details[] = { +static const struct omap3_clk_details g_omap3_clk_details[] = { - /* DMTimer modules */ - _CLK_DETAIL(DMTIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK), - _CLK_DETAIL(DMTIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK), - _CLK_DETAIL(DMTIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK), - _CLK_DETAIL(DMTIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK), - _CLK_DETAIL(DMTIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK), - _CLK_DETAIL(DMTIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK), + /* UART */ + OMAP3_GENERIC_CLOCK_DETAILS(UART1_CLK, FREQ_48MHZ, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 13), + OMAP3_GENERIC_CLOCK_DETAILS(UART2_CLK, FREQ_48MHZ, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 14), + OMAP3_GENERIC_CLOCK_DETAILS(UART3_CLK, FREQ_48MHZ, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 11), + + /* General purpose timers */ + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER1_CLK, -1, WKUP_CM_OFFSET, + 0x00, 0x10, 0x20, 3), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER2_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 3), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER3_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 4), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER4_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 5), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER5_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 6), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER6_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 7), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER7_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 8), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER8_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 9), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER9_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 10), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER10_CLK, -1, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 11), + OMAP3_GENERIC_CLOCK_DETAILS(GPTIMER11_CLK, -1, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 12), + + /* HSMMC (MMC1 and MMC2 can have different input clocks) */ + OMAP3_GENERIC_CLOCK_DETAILS(MMC1_CLK, FREQ_96MHZ, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 24), + OMAP3_GENERIC_CLOCK_DETAILS(MMC2_CLK, FREQ_96MHZ, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 25), + OMAP3_GENERIC_CLOCK_DETAILS(MMC3_CLK, FREQ_96MHZ, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 30), + + /* USB HS (high speed TLL, EHCI and OHCI) */ + OMAP3_GENERIC_CLOCK_DETAILS(USBTLL_CLK, -1, CORE_CM_OFFSET, + 0x08, 0x18, 0x28, 2), + OMAP3_GENERIC_CLOCK_DETAILS(USBHSHOST_CLK, -1, USBHOST_CM_OFFSET, + 0x00, 0x10, 0x20, 1), /* GPIO modules */ - _CLK_DETAIL(GPIO0_CLK, CM_WKUP_GPIO0_CLKCTRL, 0), - _CLK_DETAIL(GPIO1_CLK, CM_PER_GPIO1_CLKCTRL, 0), - _CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO2_CLKCTRL, 0), - _CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO3_CLKCTRL, 0), - + OMAP3_GENERIC_CLOCK_DETAILS(GPIO1_CLK, -1, WKUP_CM_OFFSET, + 0x00, 0x10, 0x20, 3), + OMAP3_GENERIC_CLOCK_DETAILS(GPIO2_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 13), + OMAP3_GENERIC_CLOCK_DETAILS(GPIO3_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 14), + OMAP3_GENERIC_CLOCK_DETAILS(GPIO4_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 15), + OMAP3_GENERIC_CLOCK_DETAILS(GPIO5_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 16), + OMAP3_GENERIC_CLOCK_DETAILS(GPIO6_CLK, -1, PER_CM_OFFSET, + 0x00, 0x10, 0x20, 17), + /* I2C modules */ - _CLK_DETAIL(I2C0_CLK, CM_WKUP_I2C0_CLKCTRL, 0), - _CLK_DETAIL(I2C1_CLK, CM_PER_I2C1_CLKCTRL, 0), - _CLK_DETAIL(I2C2_CLK, CM_PER_I2C2_CLKCTRL, 0), - - /* EDMA modules */ - _CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0), - _CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0), - _CLK_DETAIL(EDMA_TPTC1_CLK, CM_PER_TPTC1_CLKCTRL, 0), - _CLK_DETAIL(EDMA_TPTC2_CLK, CM_PER_TPTC2_CLKCTRL, 0), - - /* MMCHS modules*/ - _CLK_DETAIL(MMC0_CLK, CM_PER_MMC0_CLKCTRL, 0), - _CLK_DETAIL(MMC1_CLK, CM_PER_MMC1_CLKCTRL, 0), - _CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_CLKCTRL, 0), + OMAP3_GENERIC_CLOCK_DETAILS(I2C1_CLK, -1, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 15), + OMAP3_GENERIC_CLOCK_DETAILS(I2C2_CLK, -1, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 16), + OMAP3_GENERIC_CLOCK_DETAILS(I2C3_CLK, -1, CORE_CM_OFFSET, + 0x00, 0x10, 0x20, 17), - { INVALID_CLK_IDENT, 0}, + + { INVALID_CLK_IDENT, 0, 0, 0, 0 }, }; -/* Read/Write macros */ -#define prcm_read_4(reg) \ - bus_space_read_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg) -#define prcm_write_4(reg, val) \ - bus_space_write_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg, val) -void am335x_prcm_setup_dmtimer(int); + + + +/** + * MAX_MODULE_ENABLE_WAIT - the number of loops to wait for the module to come + * alive. + * + */ +#define MAX_MODULE_ENABLE_WAIT 1000 + + +/** + * ARRAY_SIZE - Macro to return the number of elements in a static const array. + * + */ +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + + + + +/** + * omap3_clk_wait_on_reg - loops for MAX_MODULE_ENABLE_WAIT times or until + * register bit(s) change. + * @mem_res: memory resource of the register to read + * @off: offset of the register within mem_res + * @mask: the mask to bitwise AND with the register + * @cmp: if this value matches the register value after the mask is applied + * the function returns with 0. + * + * + * RETURNS: + * Returns 0 on success or ETIMEDOUT on failure. + */ static int -am335x_prcm_probe(device_t dev) +omap3_clk_wait_on_reg(struct resource* mem_res, bus_size_t off, uint32_t mask, + uint32_t cmp) { - if (ofw_bus_is_compatible(dev, "am335x,prcm")) { - device_set_desc(dev, "AM335x Power and Clock Management"); - return(BUS_PROBE_DEFAULT); + unsigned int i; + for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) { + if ((bus_read_4(mem_res, off) & mask) == cmp) + return (0); } - return (ENXIO); + return (ETIMEDOUT); } -static int -am335x_prcm_attach(device_t dev) -{ - struct am335x_prcm_softc *sc = device_get_softc(dev); - unsigned int sysclk, fclk; - if (am335x_prcm_sc) - return (ENXIO); - if (bus_alloc_resources(dev, am335x_prcm_spec, sc->res)) { - device_printf(dev, "could not allocate resources\n"); - return (ENXIO); + + +/** + * omap3_clk_details - returns a pointer to the generic clock details + * @id: The ID of the clock to get the details for + * + * This function iterates over the g_omap3_clk_details array and returns a + * pointer to the entry that matches the supplied ID, or NULL if no entry + * is found. + * + * RETURNS: + * Pointer to clock details or NULL on failure + */ +static const struct omap3_clk_details* +omap3_clk_details(clk_ident_t id) +{ + const struct omap3_clk_details *walker; + + for (walker = g_omap3_clk_details; walker->id != INVALID_CLK_IDENT; walker++) { + if (id == walker->id) + return (walker); } - sc->bst = rman_get_bustag(sc->res[0]); - sc->bsh = rman_get_bushandle(sc->res[0]); + return NULL; +} - am335x_prcm_sc = sc; - ti_cpu_reset = am335x_prcm_reset; - am335x_clk_get_sysclk_freq(NULL, &sysclk); - am335x_clk_get_arm_fclk_freq(NULL, &fclk); - device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n", - sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000); + +/** + * omap3_clk_alwayson_null_func - dummy function for always on clocks + * @clkdev: pointer to the clock device structure (ignored) + * @mem_res: array of memory resources mapped when PRCM driver attached (ignored) + * + * + * + * LOCKING: + * Inherits the locks from the omap_prcm driver, no internal locking. + * + * RETURNS: + * Returns 0 on success or a positive error code on failure. + */ +static int +omap3_clk_alwayson_null_func(const struct ti_clock_dev *clkdev, + struct resource* mem_res[]) +{ return (0); } -static device_method_t am335x_prcm_methods[] = { - DEVMETHOD(device_probe, am335x_prcm_probe), - DEVMETHOD(device_attach, am335x_prcm_attach), - { 0, 0 } -}; -static driver_t am335x_prcm_driver = { - "am335x_prcm", - am335x_prcm_methods, - sizeof(struct am335x_prcm_softc), -}; -static devclass_t am335x_prcm_devclass; -DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver, - am335x_prcm_devclass, 0, 0); -MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1); -static struct am335x_clk_details* -am335x_clk_details(clk_ident_t id) +/** + * omap3_clk_get_sysclk_freq - gets the sysclk frequency + * @sc: pointer to the clk module/device context + * + * Read the clocking information from the power-control/boot-strap registers, + * and stored in two global variables. + * + * RETURNS: + * nothing, values are saved in global variables + */ +static int +omap3_clk_get_sysclk_freq(const struct ti_clock_dev *clkdev, + unsigned int *freq, struct resource* mem_res[]) { - struct am335x_clk_details *walker; + uint32_t clksel; + uint32_t clknsel; + unsigned int oscclk; + unsigned int sysclk; + + /* Read the input clock freq from the configuration register */ + clknsel = bus_read_4(mem_res[PRM_INSTANCE_MEM_REGION], CLOCK_CTRL_PRM_OFFSET + 0x40); + switch (clknsel & 0x7) { + case 0x0: + /* 12Mhz */ + oscclk = 12000000; + break; + case 0x1: + /* 13Mhz */ + oscclk = 13000000; + break; + case 0x2: + /* 19.2Mhz */ + oscclk = 19200000; + break; + case 0x3: + /* 26Mhz */ + oscclk = 26000000; + break; + case 0x4: + /* 38.4Mhz */ + oscclk = 38400000; + break; + case 0x5: + /* 16.8Mhz */ + oscclk = 16800000; + break; + default: + panic("%s: Invalid clock freq", __func__); + } - for (walker = g_am335x_clk_details; walker->id != INVALID_CLK_IDENT; walker++) { - if (id == walker->id) - return (walker); + /* Read the value of the clock divider used for the system clock */ + clksel = bus_read_4(mem_res[PRM_INSTANCE_MEM_REGION], GLOBAL_PRM_OFFSET + 0x70); + switch (clksel & 0xC0) { + case 0x40: + sysclk = oscclk; + break; + case 0x80: + sysclk = oscclk / 2; + break; + default: + panic("%s: Invalid system clock divider", __func__); } - return NULL; + /* Return the value */ + if (freq) + *freq = sysclk; + + return (0); } + + +/** + * omap3_clk_get_arm_fclk_freq - gets the MPU clock frequency + * @clkdev: ignored + * @freq: pointer which upon return will contain the freq in hz + * @mem_res: array of allocated memory resources + * + * Reads the frequency setting information registers and returns the value + * in the freq variable. + * + * RETURNS: + * returns 0 on success, a positive error code on failure. + */ static int -am335x_clk_generic_activate(struct ti_clock_dev *clkdev) +omap3_clk_get_arm_fclk_freq(const struct ti_clock_dev *clkdev, + unsigned int *freq, struct resource* mem_res[]) { - struct am335x_prcm_softc *sc = am335x_prcm_sc; - struct am335x_clk_details* clk_details; + unsigned int sysclk; + unsigned int coreclk; + unsigned int mpuclk; + uint32_t clksel; + uint32_t clkout; + + + /* Get the SYSCLK freq */ + omap3_clk_get_sysclk_freq(clkdev, &sysclk, mem_res); + + + /* First get the freq of the CORE_CLK (feed from DPLL3) */ + clksel = bus_read_4(mem_res[CM_INSTANCE_MEM_REGION], CLOCK_CTRL_CM_OFFSET + 0x40); + clkout = (sysclk * ((clksel >> 16) & 0x7FF)) / (((clksel >> 8) & 0x7F) + 1); + coreclk = clkout / (clksel >> 27); + + + /* Next get the freq for the MPU_CLK */ + clksel = bus_read_4(mem_res[CM_INSTANCE_MEM_REGION], MPU_CM_OFFSET + 0x40); + mpuclk = (coreclk * ((clksel >> 8) & 0x7FF)) / ((clksel & 0x7F) + 1); + + + /* Return the value */ + if (freq) + *freq = mpuclk; + + return (0); +} + + + + - if (sc == NULL) - return ENXIO; - clk_details = am335x_clk_details(clkdev->id); + + +/** + * omap3_clk_generic_activate - activates a modules iinterface and func clock + * @clkdev: pointer to the clock device structure. + * @mem_res: array of memory resources mapped when PRCM driver attached + * + * + * + * LOCKING: + * Inherits the locks from the omap_prcm driver, no internal locking. + * + * RETURNS: + * Returns 0 on success or a positive error code on failure. + */ +static int +omap3_clk_generic_activate(const struct ti_clock_dev *clkdev, + struct resource* mem_res[]) +{ + const struct omap3_clk_details* clk_details = omap3_clk_details(clkdev->id); + struct resource* clk_mem_res = mem_res[CM_INSTANCE_MEM_REGION]; + uint32_t fclken, iclken; if (clk_details == NULL) return (ENXIO); + if (clk_mem_res == NULL) + return (ENOMEM); + + + /* All the 'generic' clocks have a FCLKEN, ICLKEN and IDLEST register which + * is for the functional, interface and clock status regsters respectively. + */ + + /* Enable the interface clock */ + iclken = bus_read_4(clk_mem_res, clk_details->iclken_offset); + iclken |= (1UL << clk_details->bit_offset); + bus_write_4(clk_mem_res, clk_details->iclken_offset, iclken); + + /* Read back the value to ensure the write has taken place ... needed ? */ + iclken = bus_read_4(clk_mem_res, clk_details->iclken_offset); + + + /* Enable the functional clock */ + fclken = bus_read_4(clk_mem_res, clk_details->fclken_offset); + fclken |= (1UL << clk_details->bit_offset); + bus_write_4(clk_mem_res, clk_details->fclken_offset, fclken); + + /* Read back the value to ensure the write has taken place ... needed ? */ + fclken = bus_read_4(clk_mem_res, clk_details->fclken_offset); + + + /* Now poll on the IDLEST register to tell us if the module has come up. + * TODO: We need to take into account the parent clocks. + */ + + /* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */ + if (omap3_clk_wait_on_reg(clk_mem_res, clk_details->idlest_offset, + (1UL << clk_details->bit_offset), 0) != 0) { + printf("Error: failed to enable module with clock %d\n", clkdev->id); + return (ETIMEDOUT); + } + + return (0); +} - /* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */ - prcm_write_4(clk_details->clkctrl_reg, 2); - while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 2) - DELAY(10); + +/** + * omap3_clk_generic_deactivate - deactivates a modules clock + * @clkdev: pointer to the clock device structure. + * @mem_res: array of memory resources mapped when PRCM driver attached + * + * + * + * LOCKING: + * Inherits the locks from the omap_prcm driver, no internal locking. + * + * RETURNS: + * Returns 0 on success or a positive error code on failure. + */ +static int +omap3_clk_generic_deactivate(const struct ti_clock_dev *clkdev, + struct resource* mem_res[]) +{ + const struct omap3_clk_details* clk_details = omap3_clk_details(clkdev->id); + struct resource* clk_mem_res = mem_res[CM_INSTANCE_MEM_REGION]; + uint32_t fclken, iclken; + + if (clk_details == NULL) + return (ENXIO); + if (clk_mem_res == NULL) + return (ENOMEM); + + + /* All the 'generic' clocks have a FCLKEN, ICLKEN and IDLEST register which + * is for the functional, interface and clock status regsters respectively. + */ + + /* Disable the interface clock */ + iclken = bus_read_4(clk_mem_res, clk_details->iclken_offset); + iclken &= ~(1UL << clk_details->bit_offset); + bus_write_4(clk_mem_res, clk_details->iclken_offset, iclken); + + /* Disable the functional clock */ + fclken = bus_read_4(clk_mem_res, clk_details->fclken_offset); + fclken &= ~(1UL << clk_details->bit_offset); + bus_write_4(clk_mem_res, clk_details->fclken_offset, fclken); + + return (0); } + +/** + * omap3_clk_generic_set_source - checks if a module is accessible + * @clkdev: pointer to the clock device structure. + * + * + * + * LOCKING: + * Inherits the locks from the omap_prcm driver, no internal locking. + * *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120613205258.42647106564A>