Skip to content
brain.c 8.65 KiB
Newer Older
Papy's avatar
Papy committed
/*
    This file is part of MutekH.

    MutekH is free software; you can redistribute it and/or modify it
    under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation; version 2.1 of the
    License.

    MutekH is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this program.  If not, see
    <http://www.gnu.org/licenses/>.

    Copyright Julien Peeters <contact@julienpeeters.net> (c) 2016
*/

#include <device/device.h>
#include <device/driver.h>
#include <device/resources.h>
#include <device/irq.h>

#include <device/class/gpio.h>
#include <device/class/iomux.h>
#include <device/class/uart.h>
#include <device/class/timer.h>

#include <arch/stm32/irq.h>
#include <arch/stm32/mmap.h>
#include <arch/stm32/pin.h>

/* CPU */

DEV_DECLARE_STATIC(cpu_dev, "cpu", DEVICE_FLAG_CPU, arm32m_drv,
Papy's avatar
Papy committed
    DEV_STATIC_RES_ID(0, 0),
    DEV_STATIC_RES_FREQ(72000000, 1)
Papy's avatar
Papy committed
);

/* GPIO A..E. */
DEV_DECLARE_STATIC(gpio_dev, "gpio", 0, stm32_gpio_drv,
Papy's avatar
Papy committed
    DEV_STATIC_RES_DEV_ICU("/cpu"),
    DEV_STATIC_RES_IRQ(0, STM32_IRQ_EXTI0,     DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1),
    DEV_STATIC_RES_IRQ(1, STM32_IRQ_EXTI1,     DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1),
    DEV_STATIC_RES_IRQ(2, STM32_IRQ_EXTI2,     DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1),
    DEV_STATIC_RES_IRQ(3, STM32_IRQ_EXTI3,     DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1),
    DEV_STATIC_RES_IRQ(4, STM32_IRQ_EXTI4,     DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1),
    DEV_STATIC_RES_IRQ(5, STM32_IRQ_EXTI9_5,   DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1),
    DEV_STATIC_RES_IRQ(6, STM32_IRQ_EXTI15_10, DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1)
Papy's avatar
Papy committed
);

/* UART 4 */
DEV_DECLARE_STATIC(uart2_dev, "uart4", 0, stm32_usart_drv,
    DEV_STATIC_RES_MEM(STM32_UART4_ADDR, STM32_UART4_ADDR + STM32_UART4_SIZE),

    DEV_STATIC_RES_FREQ(72000000, 1),

    DEV_STATIC_RES_DEV_ICU("/cpu"),
    DEV_STATIC_RES_IRQ(0, STM32_IRQ_UART4, DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1),

    DEV_STATIC_RES_DEV_PARAM("iomux", "/gpio"),
    DEV_STATIC_RES_IOMUX("tx", 0, STM32_PC10, 0, 0),
    DEV_STATIC_RES_IOMUX("rx", 0, STM32_PC11, 0, 0),

    DEV_STATIC_RES_UART(19200, 8, DEV_UART_PARITY_NONE, 1, 0, 0)
);

Papy's avatar
Papy committed
DEV_DECLARE_STATIC(timer4_dev, "timer4", 0, stm32_timer_drv,
    DEV_STATIC_RES_MEM(STM32_TIM4_ADDR, STM32_TIM4_ADDR + STM32_TIM4_SIZE),

    DEV_STATIC_RES_FREQ(72000000, 1),

    DEV_STATIC_RES_DEV_ICU("/cpu"),
    DEV_STATIC_RES_IRQ(0, STM32_IRQ_TIM4, DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1),
);

#if defined(CONFIG_DRIVER_NET_DWC10100)
/* UART 4 */
DEV_DECLARE_STATIC(dwc10100_dev, "eth0", 0, dwc10100_drv,
    DEV_STATIC_RES_MEM(STM32_ETHERNET_MAC_ADDR, STM32_ETHERNET_MAC_ADDR + STM32_ETHERNET_MAC_SIZE),
    DEV_STATIC_RES_MEM(STM32_ETHERNET_MMC_ADDR, STM32_ETHERNET_MMC_ADDR + STM32_ETHERNET_MMC_SIZE),
    DEV_STATIC_RES_MEM(STM32_ETHERNET_DMA_ADDR, STM32_ETHERNET_DMA_ADDR + STM32_ETHERNET_DMA_SIZE),

    DEV_STATIC_RES_FREQ(72000000, 1),

    DEV_STATIC_RES_DEV_TIMER("rtc* timer*"),
                   
Papy's avatar
Papy committed
    DEV_STATIC_RES_DEV_IOMUX("/gpio"),
    DEV_STATIC_RES_IOMUX("mdc", 0, STM32_PC1, 0, 0),
    DEV_STATIC_RES_IOMUX("mdio", 0, STM32_PA2, 0, 0),
    DEV_STATIC_RES_IOMUX("tx_clk", 0, STM32_PC3, 0, 0),
    DEV_STATIC_RES_IOMUX("tx_en", 0, STM32_PB11, 0, 0),
    DEV_STATIC_RES_IOMUX("tx_d0", 0, STM32_PB12, 0, 0),
    DEV_STATIC_RES_IOMUX("tx_d1", 0, STM32_PB13, 0, 0),
    DEV_STATIC_RES_IOMUX("tx_d2", 0, STM32_PC2, 0, 0),
    DEV_STATIC_RES_IOMUX("tx_d3", 0, STM32_PB8, 0, 0),

    DEV_STATIC_RES_IOMUX("rx_clk", 0, STM32_PA1, 0, 0),
    DEV_STATIC_RES_IOMUX("rx_err", 0, STM32_PB10, 0, 0),
    DEV_STATIC_RES_IOMUX("rx_d0", 0, STM32_PC4, 0, 0),
    DEV_STATIC_RES_IOMUX("rx_d1", 0, STM32_PC5, 0, 0),
    DEV_STATIC_RES_IOMUX("rx_d2", 0, STM32_PB0, 0, 0),
    DEV_STATIC_RES_IOMUX("rx_d3", 0, STM32_PB1, 0, 0),
    DEV_STATIC_RES_IOMUX("rx_dv", 0, STM32_PA7, 0, 0),

    DEV_STATIC_RES_IOMUX("col", 0, STM32_PA3, 0, 0),
    DEV_STATIC_RES_IOMUX("crs", 0, STM32_PA0, 0, 0),

    //DEV_STATIC_RES_IOMUX("nirq", 0, STM32_PC8, 0, 0),
    //DEV_STATIC_RES_IOMUX("resetn", 0, STM32_PC7, 0, 0),

Papy's avatar
Papy committed
    DEV_STATIC_RES_DEV_PARAM("gpio", "/gpio"),
    DEV_STATIC_RES_GPIO("resetn", STM32_PC7, 1),

    DEV_STATIC_RES_DEV_ICU("/cpu"),
    DEV_STATIC_RES_IRQ(0, STM32_IRQ_ETH, DEV_IRQ_SENSE_HIGH_LEVEL, 0, 0x1),

    DEV_STATIC_RES_DEV_ICU("/gpio"),
    DEV_STATIC_RES_IRQ(1, STM32_PC8, DEV_IRQ_SENSE_FALLING_EDGE, 0, 1),

    DEV_STATIC_RES_BLOB_PARAM("hwaddr", ((const uint8_t[]){0x02,0x00,0x00,0x12,0x23,0x23})),
Papy's avatar
Papy committed
#include <hexo/endian.h>
#include <hexo/iospace.h>
#include <arch/stm32/f1/rcc.h>
Papy's avatar
Papy committed
#include <arch/stm32/f1/gpio.h>
Papy's avatar
Papy committed
#include <mutek/startup.h>

#define __IO volatile

struct stm32f1xx_flash_dev_s
{
  __IO uint32_t FLASH_ACR;
  __IO uint32_t FLASH_KEYR;
  __IO uint32_t FLASH_OPTKEYR;
  __IO uint32_t FLASH_SR;
  __IO uint32_t FLASH_CR;
  __IO uint32_t FLASH_AR;
  __IO uint32_t __reserved0;
  __IO uint32_t FLASH_OBR;
  __IO uint32_t FLASH_WRPR;
} __attribute__ ((packed));

#define STM32_FLASH_LAT_WS(n)   ((n) & 0x7)

void stm32_clock_init(void)
{
  uintptr_t a;
  uint32_t  x;

  __IO struct stm32f1xx_flash_dev_s *flash_dev =
    (struct stm32f1xx_flash_dev_s *) 0x40022000;

  /* Disable interrupts. */
  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_CIR_ADDR, 0);

  /* PLL OFF, PLLI2S OFF, HSE ON, HSI OFF. */
  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_CR_ADDR,
    endian_le32(STM32_RCC_CR_HSEON));

  /* Wait for hse to stabilize. */
  do
    {
      x = endian_le32(cpu_mem_read_32(STM32_RCC_ADDR + STM32_RCC_CR_ADDR));
    }
  while (!(x & STM32_RCC_CR_HSERDY));

  /* Set PLL2 @ 40MHz and PLL3 @ 50MHz */
  x = 0;
  STM32_RCC_CFGR2_PREDIV2_SET(x, 0x4 /* / 5 */);
  STM32_RCC_CFGR2_PLL2MUL_SET(x, 0x6 /* x 8 */);
  STM32_RCC_CFGR2_PLL3MUL_SET(x, 0x8 /* x 10 */);
  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_CFGR2_ADDR, endian_le32(x));

  /* Enable PLL2 @ 40MHz */
  a = STM32_RCC_ADDR + STM32_RCC_CR_ADDR;
  x = endian_le32(cpu_mem_read_32(a));
  STM32_RCC_CR_PLL2ON_SET(x, 1);
  cpu_mem_write_32(a, endian_le32(x));

  /* Wait for PLL2 to lock */
  do
    {
      x = endian_le32(cpu_mem_read_32(a));
    }
  while (!(x & STM32_RCC_CR_PLL2RDY));

  /* Enable PLL3 @ 50MHz */
  STM32_RCC_CR_PLL3ON_SET(x, 1);
  cpu_mem_write_32(a, endian_le32(x));

  /* Wait for PLL2 to lock */
  do
    {
      x = endian_le32(cpu_mem_read_32(a));
    }
  while (!(x & STM32_RCC_CR_PLL3RDY));

  /* Set PLL @ 72MHz as sink of PLL2 */
  x = endian_le32(cpu_mem_read_32(STM32_RCC_ADDR + STM32_RCC_CFGR2_ADDR));
  STM32_RCC_CFGR2_PREDIV1SRC_SET(x, 0x1 /* PLL2 */);
  STM32_RCC_CFGR2_PREDIV1_SET(x, 0x4 /* / 5 */);
  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_CFGR2_ADDR, endian_le32(x));

  x = endian_le32(cpu_mem_read_32(STM32_RCC_ADDR + STM32_RCC_CFGR_ADDR));
  STM32_RCC_CFGR_PLLSRC_SET(x, 0x1 /* PREDIV1 */);
  STM32_RCC_CFGR_PLLMUL_SET(x, 0x7 /* x 9 */);
  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_CFGR_ADDR, endian_le32(x));

  /* Enable PLL */
  a = STM32_RCC_ADDR + STM32_RCC_CR_ADDR;
  x = endian_le32(cpu_mem_read_32(a));
  STM32_RCC_CR_PLLON_SET(x, 1);
  cpu_mem_write_32(a, endian_le32(x));

  /* Wait for PLL to lock */
  do
    {
      x = endian_le32(cpu_mem_read_32(a));
    }
  while (!(x & STM32_RCC_CR_PLLRDY));

  /* set wait cycles for the flash. */
  flash_dev->FLASH_ACR = STM32_FLASH_LAT_WS(2);

  /* Configure prescalers. */
  a = STM32_RCC_ADDR + STM32_RCC_CFGR_ADDR;
  x = endian_le32(cpu_mem_read_32(a));
  STM32_RCC_CFGR_HPRE_SET(x, 0x0 /* / 1 */);    /* 72MHZ */
  STM32_RCC_CFGR_PPRE1_SET(x, 0x1 /* / 2 */);   /* 36MHZ */
  STM32_RCC_CFGR_PPRE2_SET(x, 0x0 /* / 1 */);   /* 72MHz */

  /* Use PLL-based clock path for the system clock. */
  STM32_RCC_CFGR_SW_SET(x, 0x2 /* PLL */);

  /* Set MCO clock source */
  STM32_RCC_CFGR_MCO_SET(x, 0x6 /* HSE */);
  cpu_mem_write_32(a, endian_le32(x));

  /* Wait for system clock to be sourced by the PLL. */
  do
    {
      x = endian_le32(cpu_mem_read_32(a));
    }
  while (!(x & STM32_RCC_CFGR_SWS_PLL));

  /* Enable all clock gates. */
  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_AHBENR_ADDR, -1);
  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_APB1ENR_ADDR, -1);
  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_APB2ENR_ADDR, -1);

  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_AHBRSTR_ADDR, -1);
  cpu_mem_write_32(STM32_RCC_ADDR + STM32_RCC_AHBRSTR_ADDR, 0);
Papy's avatar
Papy committed

  // Set MCO pin as alternate function
  a = STM32_GPIO_ADDR + STM32_GPIO_CRH_ADDR(0);
  x = endian_le32(cpu_mem_read_32(a));
  STM32_GPIO_CRH_CNF_SET(0, x, ALT_PUSH_PULL);
  STM32_GPIO_CRH_MODE_SET(0, x, OUTPUT_50_MHZ);
  cpu_mem_write_32(a, endian_le32(x));
Papy's avatar
Papy committed
}