|  | @@ -0,0 +1,202 @@
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * f1/floppy.c
 | 
	
		
			
				|  |  | + * 
 | 
	
		
			
				|  |  | + * Floppy interface control: STM32F103C8.
 | 
	
		
			
				|  |  | + * 
 | 
	
		
			
				|  |  | + * Written & released by Keir Fraser <keir.xen@gmail.com>
 | 
	
		
			
				|  |  | + * 
 | 
	
		
			
				|  |  | + * This is free and unencumbered software released into the public domain.
 | 
	
		
			
				|  |  | + * See the file COPYING for more details, or visit <http://unlicense.org>.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define O_FALSE 1
 | 
	
		
			
				|  |  | +#define O_TRUE  0
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define GPO_bus_pp GPO_pushpull(_2MHz,O_FALSE)
 | 
	
		
			
				|  |  | +#define AFO_bus_pp AFO_pushpull(_2MHz)
 | 
	
		
			
				|  |  | +#define GPO_bus_od GPO_opendrain(_2MHz,O_FALSE)
 | 
	
		
			
				|  |  | +#define AFO_bus_od AFO_opendrain(_2MHz)
 | 
	
		
			
				|  |  | +static unsigned int GPO_bus;
 | 
	
		
			
				|  |  | +static unsigned int AFO_bus;
 | 
	
		
			
				|  |  | +static unsigned int GPI_bus;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Input pins */
 | 
	
		
			
				|  |  | +#define gpio_index  gpiob
 | 
	
		
			
				|  |  | +#define pin_index   6 /* PB6 */
 | 
	
		
			
				|  |  | +#define gpio_trk0   gpiob
 | 
	
		
			
				|  |  | +#define pin_trk0    7 /* PB7 */
 | 
	
		
			
				|  |  | +#define gpio_wrprot gpiob
 | 
	
		
			
				|  |  | +#define pin_wrprot  8 /* PB8 */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Output pins. */
 | 
	
		
			
				|  |  | +#define gpio_dir   gpiob
 | 
	
		
			
				|  |  | +#define pin_dir    12 /* PB12 */
 | 
	
		
			
				|  |  | +#define gpio_step  gpiob
 | 
	
		
			
				|  |  | +#define pin_step   13 /* PB13 */
 | 
	
		
			
				|  |  | +#define gpio_wgate gpiob
 | 
	
		
			
				|  |  | +#define pin_wgate  14 /* PB14 */
 | 
	
		
			
				|  |  | +#define gpio_head  gpiob
 | 
	
		
			
				|  |  | +#define pin_head   15 /* PB15 */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* RDATA: Pin B3, Timer 2 Channel 2, DMA1 Channel 7. */
 | 
	
		
			
				|  |  | +#define gpio_rdata  gpiob
 | 
	
		
			
				|  |  | +#define pin_rdata   3
 | 
	
		
			
				|  |  | +#define tim_rdata   (tim2)
 | 
	
		
			
				|  |  | +#define dma_rdata   (dma1->ch7)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* WDATA: Pin B4, Timer 3 Channel 1, DMA1 Channel 3. */
 | 
	
		
			
				|  |  | +#define gpio_wdata  gpiob
 | 
	
		
			
				|  |  | +#define pin_wdata   4
 | 
	
		
			
				|  |  | +#define tim_wdata   (tim3)
 | 
	
		
			
				|  |  | +#define dma_wdata   (dma1->ch3)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +typedef uint16_t timcnt_t;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#define irq_index 23
 | 
	
		
			
				|  |  | +void IRQ_23(void) __attribute__((alias("IRQ_INDEX_changed"))); /* EXTI9_5 */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static unsigned int U_BUF_SZ;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void floppy_mcu_init(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const struct pin_mapping *mpin;
 | 
	
		
			
				|  |  | +    const struct pin_mapping *upin;
 | 
	
		
			
				|  |  | +    unsigned int avail_kb;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    avail_kb = sram_kb - ((((unsigned long)_ebss - 0x20000000) + 1023) >> 10);
 | 
	
		
			
				|  |  | +    for (U_BUF_SZ = 128; U_BUF_SZ > avail_kb; U_BUF_SZ >>= 1)
 | 
	
		
			
				|  |  | +        continue;
 | 
	
		
			
				|  |  | +    U_BUF_SZ <<= 10;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    switch (gw_info.hw_submodel) {
 | 
	
		
			
				|  |  | +    case F1SM_basic:
 | 
	
		
			
				|  |  | +        /* Determine whether input pins must be internally pulled down. */
 | 
	
		
			
				|  |  | +        configure_pin(index, GPI_pull_down);
 | 
	
		
			
				|  |  | +        delay_us(10);
 | 
	
		
			
				|  |  | +        GPI_bus = (get_index() == LOW) ? GPI_pull_up : GPI_floating;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    case F1SM_plus:
 | 
	
		
			
				|  |  | +    case F1SM_plus_unbuffered:
 | 
	
		
			
				|  |  | +        GPI_bus = GPI_floating;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    printk("Floppy Inputs: %sternal Pullup\n",
 | 
	
		
			
				|  |  | +           (GPI_bus == GPI_pull_up) ? "In" : "Ex");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* Remap timers to RDATA/WDATA pins. */
 | 
	
		
			
				|  |  | +    afio->mapr |= (AFIO_MAPR_TIM2_REMAP_PARTIAL_1
 | 
	
		
			
				|  |  | +                   | AFIO_MAPR_TIM3_REMAP_PARTIAL);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    configure_pin(rdata, GPI_bus);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* Configure user-modifiable pins. */
 | 
	
		
			
				|  |  | +    for (upin = board_config->user_pins; upin->pin_id != 0; upin++) {
 | 
	
		
			
				|  |  | +        gpio_configure_pin(gpio_from_id(upin->gpio_bank), upin->gpio_pin,
 | 
	
		
			
				|  |  | +                           upin->push_pull ? GPO_bus_pp : GPO_bus_od);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* Configure the standard output types. */
 | 
	
		
			
				|  |  | +    GPO_bus = upin->push_pull ? GPO_bus_pp : GPO_bus_od;
 | 
	
		
			
				|  |  | +    AFO_bus = upin->push_pull ? AFO_bus_pp : AFO_bus_od;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* Configure SELECT/MOTOR lines. */
 | 
	
		
			
				|  |  | +    for (mpin = board_config->msel_pins; mpin->pin_id != 0; mpin++) {
 | 
	
		
			
				|  |  | +        gpio_configure_pin(gpio_from_id(mpin->gpio_bank), mpin->gpio_pin,
 | 
	
		
			
				|  |  | +                           GPO_bus);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* Set up EXTI mapping for INDEX: PB[15:0] -> EXT[15:0] */
 | 
	
		
			
				|  |  | +    afio->exticr1 = afio->exticr2 = afio->exticr3 = afio->exticr4 = 0x1111;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void rdata_prep(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    /* RDATA Timer setup: 
 | 
	
		
			
				|  |  | +     * The counter runs from 0x0000-0xFFFF inclusive at SAMPLE rate.
 | 
	
		
			
				|  |  | +     *  
 | 
	
		
			
				|  |  | +     * Ch.2 (RDATA) is in Input Capture mode, sampling on every clock and with
 | 
	
		
			
				|  |  | +     * no input prescaling or filtering. Samples are captured on the falling 
 | 
	
		
			
				|  |  | +     * edge of the input (CCxP=1). DMA is used to copy the sample into a ring
 | 
	
		
			
				|  |  | +     * buffer for batch processing in the DMA-completion ISR. */
 | 
	
		
			
				|  |  | +    tim_rdata->psc = TIM_PSC-1;
 | 
	
		
			
				|  |  | +    tim_rdata->arr = 0xffff;
 | 
	
		
			
				|  |  | +    tim_rdata->ccmr1 = TIM_CCMR1_CC2S(TIM_CCS_INPUT_TI1);
 | 
	
		
			
				|  |  | +    tim_rdata->dier = TIM_DIER_CC2DE;
 | 
	
		
			
				|  |  | +    tim_rdata->cr2 = 0;
 | 
	
		
			
				|  |  | +    tim_rdata->egr = TIM_EGR_UG; /* update CNT, PSC, ARR */
 | 
	
		
			
				|  |  | +    tim_rdata->sr = 0; /* dummy write */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* RDATA DMA setup: From the RDATA Timer's CCRx into a circular buffer. */
 | 
	
		
			
				|  |  | +    dma_rdata.par = (uint32_t)(unsigned long)&tim_rdata->ccr2;
 | 
	
		
			
				|  |  | +    dma_rdata.cr = (DMA_CR_PL_HIGH |
 | 
	
		
			
				|  |  | +                    DMA_CR_MSIZE_16BIT |
 | 
	
		
			
				|  |  | +                    DMA_CR_PSIZE_16BIT |
 | 
	
		
			
				|  |  | +                    DMA_CR_MINC |
 | 
	
		
			
				|  |  | +                    DMA_CR_CIRC |
 | 
	
		
			
				|  |  | +                    DMA_CR_DIR_P2M |
 | 
	
		
			
				|  |  | +                    DMA_CR_EN);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    tim_rdata->ccer = TIM_CCER_CC2E | TIM_CCER_CC2P;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void wdata_prep(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    /* WDATA Timer setup:
 | 
	
		
			
				|  |  | +     * The counter is incremented at SAMPLE rate. 
 | 
	
		
			
				|  |  | +     *  
 | 
	
		
			
				|  |  | +     * Ch.1 (WDATA) is in PWM mode 1. It outputs O_TRUE for 400ns and then 
 | 
	
		
			
				|  |  | +     * O_FALSE until the counter reloads. By changing the ARR via DMA we alter
 | 
	
		
			
				|  |  | +     * the time between (fixed-width) O_TRUE pulses, mimicking floppy drive 
 | 
	
		
			
				|  |  | +     * timings. */
 | 
	
		
			
				|  |  | +    tim_wdata->psc = TIM_PSC-1;
 | 
	
		
			
				|  |  | +    tim_wdata->ccmr1 = (TIM_CCMR1_CC1S(TIM_CCS_OUTPUT) |
 | 
	
		
			
				|  |  | +                        TIM_CCMR1_OC1M(TIM_OCM_PWM1));
 | 
	
		
			
				|  |  | +    tim_wdata->ccer = TIM_CCER_CC1E | ((O_TRUE==0) ? TIM_CCER_CC1P : 0);
 | 
	
		
			
				|  |  | +    tim_wdata->ccr1 = sample_ns(400);
 | 
	
		
			
				|  |  | +    tim_wdata->dier = TIM_DIER_UDE;
 | 
	
		
			
				|  |  | +    tim_wdata->cr2 = 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void dma_wdata_start(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    dma_wdata.cr = (DMA_CR_PL_HIGH |
 | 
	
		
			
				|  |  | +                    DMA_CR_MSIZE_16BIT |
 | 
	
		
			
				|  |  | +                    DMA_CR_PSIZE_16BIT |
 | 
	
		
			
				|  |  | +                    DMA_CR_MINC |
 | 
	
		
			
				|  |  | +                    DMA_CR_CIRC |
 | 
	
		
			
				|  |  | +                    DMA_CR_DIR_M2P |
 | 
	
		
			
				|  |  | +                    DMA_CR_EN);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static uint8_t mcu_get_floppy_pin(unsigned int pin, uint8_t *p_level)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    switch (gw_info.hw_submodel) {
 | 
	
		
			
				|  |  | +    case F1SM_plus:
 | 
	
		
			
				|  |  | +    case F1SM_plus_unbuffered:
 | 
	
		
			
				|  |  | +        if (pin == 34) {
 | 
	
		
			
				|  |  | +            *p_level = gpio_read_pin(gpioa, 8);
 | 
	
		
			
				|  |  | +            return ACK_OKAY;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return ACK_BAD_PIN;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void flippy_trk0_sensor(bool_t level)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (board_config->flippy) {
 | 
	
		
			
				|  |  | +        gpio_write_pin(gpioa, 2, level);
 | 
	
		
			
				|  |  | +        delay_us(10);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * Local variables:
 | 
	
		
			
				|  |  | + * mode: C
 | 
	
		
			
				|  |  | + * c-file-style: "Linux"
 | 
	
		
			
				|  |  | + * c-basic-offset: 4
 | 
	
		
			
				|  |  | + * tab-width: 4
 | 
	
		
			
				|  |  | + * indent-tabs-mode: nil
 | 
	
		
			
				|  |  | + * End:
 | 
	
		
			
				|  |  | + */
 |